@educa-corp/sdd-framework 0.8.1 → 0.9.1

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 (66) hide show
  1. package/bin/lint-trace.js +200 -1
  2. package/bin/self-check.js +0 -146
  3. package/bin/trace-schema.json +12 -3
  4. package/core/FRAMEWORK_VERSION +1 -1
  5. package/core/commands/generate-code.md +45 -2
  6. package/core/commands/propose-scenario.md +1 -1
  7. package/core/commands/qc-analyze.md +22 -260
  8. package/core/commands/qc-design-test.md +1 -1
  9. package/core/commands/qc-plan.md +4 -7
  10. package/core/commands/qc-run-test.md +1 -1
  11. package/core/commands/refine-prd.md +20 -47
  12. package/core/commands/report-bug.md +1 -1
  13. package/core/commands/review-context.md +1 -27
  14. package/core/commands/validate-traces.md +178 -3
  15. package/core/skills/qc/qa-analyst/DOC_GAPS.template.md +63 -0
  16. package/core/skills/qc/qa-analyst/acceptance-criteria.md +2 -4
  17. package/core/skills/qc/qa-analyst/business-rules.md +4 -38
  18. package/core/skills/qc/qa-analyst/data-flow.md +3 -5
  19. package/core/skills/qc/qa-analyst/spec-breakdown.md +7 -9
  20. package/core/skills/qc/qa-designer/e2e/journey.md +2 -2
  21. package/core/skills/qc/qa-designer/exploratory/charter.md +1 -1
  22. package/core/skills/qc/qa-designer/exploratory/explore-to-functional.md +1 -1
  23. package/core/skills/qc/qa-designer/functional/api.md +2 -2
  24. package/core/skills/qc/qa-designer/functional/gui-feature.md +2 -2
  25. package/core/skills/qc/qa-designer/functional/gui-screen.md +2 -2
  26. package/core/skills/qc/qa-designer/integration/api.md +2 -2
  27. package/core/skills/qc/qa-designer/integration/db.md +2 -2
  28. package/core/skills/qc/qa-designer/integration/gui.md +2 -2
  29. package/core/skills/qc/qa-designer/integration/kafka.md +2 -2
  30. package/core/skills/qc/qa-designer/non-functional.md +2 -2
  31. package/core/skills/qc/qa-planner/test-plan.md +10 -13
  32. package/core/skills/qc/qa-reviewer/script/e2e.md +1 -1
  33. package/core/skills/qc/qa-reviewer/script/exploratory.md +1 -1
  34. package/core/skills/qc/qa-reviewer/script/functional.md +1 -1
  35. package/core/skills/qc/qa-reviewer/script/integration.md +1 -1
  36. package/core/skills/qc/qa-reviewer/script/non-functional.md +1 -1
  37. package/core/skills/qc/qa-reviewer/test-case/e2e.md +1 -1
  38. package/core/skills/qc/qa-reviewer/test-case/exploratory.md +1 -1
  39. package/core/skills/qc/qa-reviewer/test-case/functional.md +1 -1
  40. package/core/skills/qc/qa-reviewer/test-case/integration.md +2 -2
  41. package/core/skills/qc/qa-reviewer/test-case/non-functional.md +1 -1
  42. package/core/skills/qc/qa-runner/e2e.md +1 -1
  43. package/core/skills/qc/qa-runner/exploratory/session.md +1 -1
  44. package/core/skills/qc/qa-runner/functional/api.md +1 -1
  45. package/core/skills/qc/qa-runner/functional/gui-feature.md +1 -1
  46. package/core/skills/qc/qa-runner/functional/gui-screen.md +1 -1
  47. package/core/skills/qc/qa-runner/integration.md +1 -1
  48. package/core/skills/qc/qa-runner/non-functional.md +1 -1
  49. package/core/skills/qc/qa-runner/report/report.md +1 -1
  50. package/core/steps/review-fanout.md +1 -27
  51. package/core/templates/project-context.yaml +2 -2
  52. package/docs/02-concepts/pipeline-steps/08-qc-automation.md +2 -2
  53. package/docs/04-reference/commands.md +1 -1
  54. package/docs/explain/03-refine-prd.md +6 -8
  55. package/docs/explain/15-qc-analyze.md +7 -10
  56. package/docs/explain/16-qc-plan.md +2 -2
  57. package/package.json +3 -2
  58. package/bin/qc-base-map.json +0 -595
  59. package/core/skills/qc/qa-analyst/DOC_GAP.template.md +0 -117
  60. package/core/skills/qc/qa-analyst/exhaustive-gap-scanner.md +0 -174
  61. package/core/skills/qc/qa-analyst/spec-issue-reporter.md +0 -100
  62. package/core/skills/qc/qa-planner/risk-model.md +0 -106
  63. package/core/steps/gap-verify.md +0 -231
  64. package/docs/plans/qc-implementation-log.md +0 -1446
  65. package/docs/plans/qc-merge-plan.md +0 -502
  66. package/docs/plans/qc-sync-command.md +0 -358
@@ -1,502 +0,0 @@
1
- # Kế hoạch sáp nhập dây chuyền QC vào framework
2
-
3
- > Đội QC đang chạy một dây chuyền AI automation test **7 agent / 45 skill** bên ngoài framework
4
- > (`D:\projects\ui-automation-testing`). Framework có **6 trạm QC / 35 skill file**.
5
- > Tài liệu này giải thích cả hai đang làm gì, ba chỗ chúng va nhau, và cách gộp lại.
6
-
7
- | | |
8
- |---|---|
9
- | Repo | `sdd-framework @ main` |
10
- | Nguồn QC | `ui-automation-testing` (`.claude/agents/3-qa-tc-analyst.md` + `.claude/skills/qa-tc-analyst/`) |
11
- | Trạng thái | chờ 3 quyết định (§5) |
12
- | Cập nhật | 2026-08-22 |
13
-
14
- **Mục lục**
15
-
16
- 1. [Cốt lõi: framework cần *sổ cái*, không cần report](#1)
17
- 2. [Framework: sáu trạm, đi theo một UC](#2)
18
- 3. [Đội QC: bảy agent, ba lane](#3)
19
- 4. [Ánh xạ hai bên](#4)
20
- 5. [Ba quyết định](#5)
21
- 6. [Món quà đi ngược chiều](#6)
22
- 7. [Plan năm phase](#7)
23
- 8. [Bốn lỗi tìm được khi đọc `/qc-analyze`](#8)
24
-
25
- ---
26
-
27
- <a id="1"></a>
28
- ## 1 · Cốt lõi: framework cần *sổ cái*, không cần report
29
-
30
- > Hiểu điều này trước, mọi thiết kế còn lại tự giải thích.
31
-
32
- Trước khi QC vào việc, framework đã có sẵn ba thứ do các phase trước sinh ra.
33
- Ví dụ thật: feature `FT-001-free-trial`, use case `FT-001-UC4` (làm survey), platform `web`.
34
-
35
- ```
36
- specs/onboarding/free-trial/
37
- ├── FT-001-free-trial.md PRD — PO viết, đã approved
38
- ├── bdd/web/FT-001-UC4.feature Gherkin — mỗi scenario một ID:
39
- │ FT-001-UC4-SC1, SC2, SC3…
40
- └── tech-docs/FT-001-tech-design.md §4.5.6 có bảng test-id
41
-
42
- .trace/onboarding/free-trial/
43
- └── FT-001-UC4-web.tsv ← SỔ CÁI. 1 dòng = 1 scenario.
44
- ```
45
-
46
- File `.tsv` đó là trái tim của framework:
47
-
48
- | sc_id | status | dev_selftest | qc_status | qc_owner | qc_blocked_by |
49
- |---|---|---|---|---|---|
50
- | FT-001-UC4-SC1 | OK | pass | `not_run` | `—` | `—` |
51
- | FT-001-UC4-SC2 | OK | pass | `not_run` | `—` | `—` |
52
- | FT-001-UC4-SC3 | DRIFT | pass | `not_run` | `—` | `—` |
53
-
54
- > **Điểm mấu chốt:** toàn bộ 6 trạm QC tồn tại để điền **ba cột `qc_*`** đó.
55
- > Không phải để ra report.
56
-
57
- Khác biệt giữa report và sổ cái không phải khác biệt hình thức — nó là khác biệt **cơ chế**:
58
-
59
- ```
60
- A · DÂY CHUYỀN QC ĐỘC LẬP
61
-
62
- spec ─► phân tích ─► test case ─► script ─► chạy ─► report.html ─┤
63
-
64
- tài liệu chết — ai không mở thì không biết
65
-
66
-
67
- B · FRAMEWORK
68
-
69
- spec ─► phân tích ─► test case ─► script ─► chạy ─GHI─► ┌──────────────┐
70
- │ SỔ CÁI │
71
- │ .tsv │
72
- │ qc_status │
73
- └──┬────────┬──┘
74
- tín hiệu │ │
75
- sống │ │
76
- ┌───────────────◄┘ └►───────────────┐
77
- │ dashboard PO / PM │ │ cổng chặn PR │
78
- └───────────────────┘ └───────────────┘
79
-
80
- qc_status = fail → cổng chặn merge
81
- qc_owner = dev → dashboard hiện "SC này đang chờ dev"
82
- qc_owner = po → đang chờ PO làm rõ tài liệu
83
- ```
84
-
85
- **Report là tài liệu chết; `qc_status` là tín hiệu sống.**
86
- Report nằm im chờ người mở. Sổ cái thì chặn PR, điều khiển dashboard, và nói được
87
- "scenario này đang chờ ai".
88
-
89
- → Nên khi đưa dây chuyền QC vào framework, thứ framework thực sự cần từ nó **không phải**
90
- DOC_GAP hay TEST_PLAN — mà là: *cuối cùng có ghi được `qc_status` đúng cho từng scenario
91
- hay không?* Mọi thứ khác là phương tiện.
92
-
93
- ---
94
-
95
- <a id="2"></a>
96
- ## 2 · Framework: sáu trạm, đi theo một UC
97
-
98
- > Mỗi trạm là một lệnh riêng, giao việc cho trạm sau **bằng file**.
99
-
100
- ```
101
- TRẠM 1 TRẠM 2 TRẠM 3 TRẠM 4 TRẠM 5 TRẠM 6
102
- /qc-analyze ─►/qc-plan ─► /qc-design-test ─►/qc-review ─►/qc-run-test ─►/qc-report
103
- │ │ │ ↑ │ │ │
104
- │ │ │ └──┘ │ │
105
- │ │ │ chạy 2 lần: │ │
106
- │ │ │ review test-case, │ │
107
- │ │ │ rồi review script │ │
108
- ▼ ▼ ▼ ▼ ▼
109
- ┌─────────────┐ ┌──────────┐ ┌────────────┐ ┌───────────┐ ┌────────────┐
110
- │REQUIREMENT_ │ │TEST_PLAN │ │*.Test.md │ │tests/*.py │ │report.html │
111
- │ANALYSIS.md │ │.md │ │@trace. │ └─────┬─────┘ │trace.zip │
112
- ├─────────────┤ └──────────┘ │ verifies= │ │ └────────────┘
113
- │DOC_GAPS.md │ │ SC2 │ GHI qc_status
114
- └──────┬──────┘ └────────────┘ │
115
- │ ▼
116
- │ ┌──────────────────────────────┐ ┌──────────────────┐
117
- └─►│ trạm 2 VÀ trạm 3 đều ĐỌC lại │ │ SỔ CÁI .tsv │
118
- │ file này ←── đây là CÂU 1 │ └──────────────────┘
119
- └──────────────────────────────┘
120
- ```
121
-
122
- **Trạm 5 còn hai đặc quyền riêng:**
123
-
124
- - **Chủ sở hữu duy nhất** của bước bug `🟡 Fixed → 🟢 Closed`.
125
- `/report-bug` mở bug, `/fix-bug` đặt `Fixed`, và **chỉ QC chạy lại mới được đóng**.
126
- - **Guard G55 — quyền được nói "pass".**
127
- SC3 test XANH, nhưng `status = DRIFT` (spec đã đổi sau khi sinh code)
128
- → ghi `not_run`, **KHÔNG** ghi `pass`, **KHÔNG** đóng bug nào.
129
- *Test xanh trên spec cũ không được quyền nói "đã nghiệm thu".*
130
-
131
- ### Từng trạm, bằng một câu
132
-
133
- | # | Lệnh | Câu hỏi nó trả lời | Ghi ra |
134
- |---|---|---|---|
135
- | 1 | `/qc-analyze` | Yêu cầu này **là gì?** Bóc thành BR-01…, AC-01…, mỗi cái ghi rõ thuộc scenario nào. | `REQUIREMENT_ANALYSIS.md`<br>`DOC_GAPS.md` |
136
- | 2 | `/qc-plan` | Rủi ro **ở đâu**, phải hỏi dev gì? Risk matrix, what-if, entry/exit criteria. | `TEST_PLAN.md` |
137
- | 3 | `/qc-design-test` | Test case cụ thể. Markdown, chưa có code. TC bị chặn bởi gap vẫn viết, đánh dấu `🚫 Block: GAP-03`. | `test-cases/*.Test.md` |
138
- | 4 | `/qc-review` | Cổng. Chạy **hai lần** — lần 1 review test case, lần 2 review script Python. | verdict |
139
- | 5 | `/qc-run-test` | Sinh Python, chạy, **ghi sổ cái**. Trạm quan trọng nhất. | `tests/*.py` + `qc_status` |
140
- | 6 | `/qc-report` | Evidence + đẩy defect thật về spec (in ra lệnh `/report-bug` sẵn chạy). | `report.html`, `trace.zip` |
141
-
142
- ### Sau khi trạm 5 chạy, sổ cái trông thế này
143
-
144
- | sc_id | status | qc_status | qc_owner | qc_blocked_by | Nghĩa là |
145
- |---|---|---|---|---|---|
146
- | SC1 | OK | `pass` | `—` | `—` | Xong. Nghiệm thu theo spec hiện tại. |
147
- | SC2 | OK | `fail` | **dev** | BUG-012 | Lỗi thật. Dashboard hiện "chờ dev". Cổng chặn PR. |
148
- | SC3 | DRIFT | `not_run` | `—` | `—` | Test xanh, nhưng spec đã đổi → không được quyền nói pass. |
149
-
150
- ---
151
-
152
- <a id="3"></a>
153
- ## 3 · Đội QC: bảy agent, ba lane
154
-
155
- > Cùng công việc, nhưng cắt theo một **trục khác**.
156
-
157
- ```
158
- ┌───── REJECT → sửa lại ─────┐
159
- ▼ │
160
- inputs/ ─►(1)──────────►(2)───────────►(3)──────────►(4)───────────►(5)──────►(6)──────►(7)
161
- qa-io-contract qa-orchestrator qa-tc-analyst qa-tc-designer qa-tc- qa-runner qa-gate
162
- 2 skill 2 skill 18 skill 5 skill reviewer 2 skill 5 skill
163
- validate input, routing 3 lane 11 skill
164
- quét injection
165
- └────────────────────────────────────┘
166
- 3 LANE XUYÊN SUỐT: UI · API · E2E
167
- lane API tự SKIP hoàn toàn nếu
168
- không có openapi / dbml / tdd
169
-
170
-
171
- ┌──────────────────────┐
172
- │ QA_GATE_REPORT.md │──┤
173
- └──────────────────────┘
174
- không có sổ cái
175
-
176
- AUTO-CHAINING: gọi agent 6 mà thiếu output 3/4/5 → tự chạy 3 → 4 → 5 trước.
177
- ```
178
-
179
- **Ba lane là trục chính của đội QC, xuất hiện trong mọi agent.**
180
- Framework không có trục này — nó cắt theo *layer* (functional / integration / e2e /
181
- non-functional / exploratory) **nhân với** *platform* (web / app / system).
182
- Hai trục không mâu thuẫn, nhưng cắt chéo nhau — xem §4.
183
-
184
- ---
185
-
186
- <a id="4"></a>
187
- ## 4 · Ánh xạ hai bên
188
-
189
- > Bốn trạm khớp gần như hoàn hảo. Vấn đề dồn hết vào một chỗ.
190
-
191
- | # | Đội QC | Framework | Tình trạng |
192
- |---|---|---|---|
193
- | 1 | `qa-io-contract` — 2 skill, validate input + quét prompt-injection | *không có* — thay bằng `gate` + `context-loader` | ⚠️ **thiếu** Framework mất phần chống injection. Spec là dữ liệu để đọc, không phải mệnh lệnh — đội bạn có gác, framework không. |
194
- | 2 | `qa-orchestrator` — 2 skill, routing 3 lane | *không có* — thay bằng `Platform Resolution` | ⚠️ **lệch trục** lane ↔ platform |
195
- | **3** | **`qa-tc-analyst` — 18 skill** | **`/qc-analyze` (4) + `/qc-plan` (1)** | 🔴 **CHỖ ĐANG LÀM.** Framework cắt 1 agent thành 2 trạm, và chỉ lấy 5/18 skill. |
196
- | 4 | `qa-tc-designer` — 5 skill | `/qc-design-test` — 11 file | ✅ khớp, framework còn phong phú hơn |
197
- | 5 | `qa-tc-reviewer` — 11 skill | `/qc-review` — 10 file | ✅ khớp |
198
- | 6 | `qa-runner` — 2 skill | `/qc-run-test` — 7 file *+ ghi sổ cái + đóng bug* | ✅ framework làm nhiều hơn |
199
- | 7 | `qa-gate` — 5 skill | `/qc-report` — 1 file | ⚠️ **mỏng hơn** framework thiếu `coverage-evaluator`, `risk-matrix-builder`, `gate-decision` |
200
-
201
- ### Điều có lẽ chưa biết
202
-
203
- Framework hiện tại port từ nhánh **`lms_autotest`**, không phải nhánh hợp nhất đang chạy.
204
- Bằng chứng nằm trong chính file agent của đội QC:
205
-
206
- ```
207
- ## Skill bổ sung (hợp nhất từ lms_autotest)
208
- spec-breakdown · business-rules · data-flow · acceptance-criteria · test-plan
209
- ```
210
-
211
- **Đúng năm cái đó, không hơn không kém, là toàn bộ những gì framework đang có ở trạm 1 + 2.**
212
- Framework lấy đúng phần *phụ trợ* của nhánh cũ và bỏ lại 13 skill lõi của nhánh mới.
213
- (`test-plan` thì bị đẩy sang `qa-planner/` = trạm 2.)
214
-
215
- ### Trục cắt chéo nhau — nhìn cụ thể
216
-
217
- ```
218
- LAYER CỦA FRAMEWORK LANE CỦA ĐỘI QC
219
- UI API E2E (không có lane)
220
- functional/gui-screen [✓]
221
- functional/gui-feature [✓]
222
- integration/gui [✓]
223
- functional/api [✓]
224
- integration/api [✓]
225
- e2e/journey [✓]
226
- integration/db [░░░░░░░░] ┐
227
- integration/kafka [░░░░░░░░] │ 4 layer framework
228
- non-functional [░░░░░░░░] │ không có lane
229
- exploratory [░░░░░░░░] ┘ tương ứng
230
-
231
- + TRỤC THỨ HAI mà QC không có: platform (web / app / system)
232
- → mỗi QC pass của framework khoá đúng MỘT platform, vì SC3 của web
233
- và SC3 của app là hai scenario khác nhau, ghi vào hai file sổ cái khác nhau.
234
- ```
235
-
236
- ---
237
-
238
- <a id="5"></a>
239
- ## 5 · Ba quyết định
240
-
241
- > Cả ba đều **không phải lỗi kỹ thuật** — chúng là chỗ hai đội định nghĩa "giao hàng" khác nhau.
242
-
243
- Kỳ vọng đặt ra cho `/qc-analyze` là hai chế độ:
244
-
245
- - **Mặc định** — trả GAP theo đúng định dạng mà `/refine-prd` sinh ra, như một lăng kính của QA.
246
- - **`--standard`** — trả đúng kết quả gốc mà đội automation test đang làm.
247
-
248
- Ba câu dưới đây là những chỗ hai chế độ đó chạm vào ranh giới đang có của framework.
249
-
250
- ### Hình chung cho câu 1 và câu 2
251
-
252
- ```
253
- CÁCH ĐỘI QC CẮT CÁCH FRAMEWORK CẮT
254
-
255
- ┌──────────────────────┐ ┌────────────────────┐
256
- │ qa-tc-analyst │ │ /qc-analyze │
257
- │ một agent làm cả 3 │ │ ① bóc yêu cầu │──► REQUIREMENT_ANALYSIS.md
258
- │ ───────────────── │ │ ② tìm gap │──► DOC_GAPS.md
259
- │ ① bóc yêu cầu │ └─────────┬──────────┘
260
- │ ② tìm gap tài liệu │ ▼
261
- │ ③ lập test plan │ ┌────────────────────┐
262
- └──────────┬───────────┘ │ /qc-plan │
263
- │ │ ③ lập test plan │──► TEST_PLAN.md
264
- ├──► ✕ requirement analysis └────────────────────┘
265
- │ — giấy nháp, KHÔNG xuất
266
- ├──► DOC_GAP_<UC>.md
267
- └──► TEST_PLAN_<UC>.md
268
-
269
- VÌ SAO CẢ HAI ĐỀU ĐÚNG
270
- Đội QC làm ba việc trong MỘT agent → file ① là nháp nội bộ, không cần giao cho ai.
271
- Framework tách thành BA lệnh riêng → file ① phải tồn tại vì trạm 2 và trạm 3 đọc nó.
272
- → "đúng gốc" theo nghĩa chữ sẽ làm trạm 2 và trạm 3 MẤT INPUT.
273
- ```
274
-
275
- ---
276
-
277
- ### CÂU 1 — `REQUIREMENT_ANALYSIS.md`: giữ hay bỏ?
278
-
279
- Đội QC nói file này là **giấy nháp**:
280
- *"phân tích rủi ro / AC / TCOND chỉ là bước trung gian nội bộ, KHÔNG phải deliverable"*.
281
- Framework coi nó là **hợp đồng giao hàng** — `qc-plan.md:165` và `qc-design-test.md:165`
282
- đều khai rõ là đọc nó.
283
-
284
- > **Hỏi lại cho dễ:** khi chạy `--standard`, có chấp nhận nó vẫn âm thầm ghi ra một file nháp
285
- > mà QC không cần mở — chỉ để trạm 2 và trạm 3 đọc được — hay "đúng gốc" nghĩa là
286
- > *tuyệt đối* không có file đó?
287
-
288
- | Chọn | Nghĩa là | Giá phải trả |
289
- |---|---|---|
290
- | **Vẫn ghi** *(khuyến nghị)* | Giữ hợp đồng giữa các trạm. Coi nó là handoff nội bộ, không phải deliverable của QC. | Không phải sửa gì downstream. QC chỉ cần không mở nó. |
291
- | Bỏ, trạm 2/3 đọc DOC_GAP | Trung thành 100% với gốc QC. | Sửa cả `qc-plan` + `qc-design-test`, và dựng lại phần requirement chúng đang cần từ nguồn khác. |
292
- | Bỏ, thay bằng `findings.yaml` | Trạm 2/3 đọc dữ liệu máy-đọc-được thay vì hai file `.md`. | Refactor ba lệnh cùng lúc. Sạch nhất về lâu dài, đắt nhất bây giờ. |
293
-
294
- ---
295
-
296
- ### CÂU 2 — `TEST_PLAN`: của trạm 1 hay trạm 2?
297
-
298
- Đội QC: analyst xuất **cả** DOC_GAP **và** TEST_PLAN, xong việc phân tích.
299
- Framework: DOC_GAP ở trạm 1, TEST_PLAN ở trạm 2 (skill `qa-planner/test-plan.md` —
300
- chính là skill `test-plan` của đội QC, đã bị đẩy sang trạm khác).
301
-
302
- > **Hỏi lại cho dễ:** muốn đội QC gõ **một lệnh** ra cả hai file (giống họ đang làm),
303
- > hay **hai lệnh liền nhau** ra hai file (giữ đúng sáu trạm của framework)?
304
-
305
- | Chọn | Nghĩa là | Giá phải trả |
306
- |---|---|---|
307
- | **Thêm `--standard` cho cả `/qc-plan`** *(khuyến nghị)* | QC gõ hai lệnh liền nhau, kết quả giống dây gốc của họ. Ranh giới sáu trạm giữ nguyên. | Đội QC phải học là "phân tích" giờ là hai lệnh. |
308
- | Trạm 1 xuất luôn cả hai file | Khớp gốc bằng đúng một lệnh. | Trạm 2 thành no-op khi đã `--standard` — phải khai rõ để không ai chạy trùng và ghi đè. |
309
- | Gộp trạm 1 + trạm 2 | Thừa nhận framework đã tách sai so với thực tế đội QC. | Đụng `docs/explain`, `report-footer`, và mọi chỗ khai "pipeline 6 trạm". |
310
-
311
- ---
312
-
313
- ### CÂU 3 — Kết quả GAP đi vào file nào?
314
-
315
- Framework có một thứ gọi là **Review Board** — bảng mà PO click chuột phải vào file `.yaml`
316
- để mở, đọc từng finding, bấm accept hoặc reject, rồi lệnh `--resume` *tự sửa PRD* theo
317
- những cái đã accept.
318
-
319
- Hiện `/refine-prd` sinh file `{prd-slug}-findings.yaml` với ba lăng kính **DEV · SA · PO**.
320
- Có một **lăng kính QA thứ tư đã viết sẵn nhưng bị comment lại** — kèm công thức bật lại
321
- năm bước, ở `commands/refine-prd.tmpl:60-79`. Nội dung nó hỏi:
322
- *"AC này có nêu được kết quả quan sát / kiểm chứng được không?"* — đúng góc nhìn QC.
323
-
324
- ```
325
- CÁCH A · FILE RIÊNG, CÙNG ĐỊNH DẠNG
326
-
327
- /refine-prd ──► {prd-slug}-findings.yaml (DEV, SA, PO) ─┐
328
- ├─► Review Board
329
- /qc-analyze ──► {UC-ID}-qa-findings.yaml (QA) ─┘ đọc được cả hai —
330
- vì cùng một schema
331
-
332
- CÁCH B · CHUNG MỘT FILE
333
-
334
- /refine-prd ──┐
335
- ├─► {prd-slug}-findings.yaml
336
- /qc-analyze ──┘ applied_to_version: ???
337
-
338
-
339
- refine-prd MẤT KHẢ NĂNG PHÂN BIỆT
340
- "PRD đổi là do CHÍNH TÔI áp fix" ↔ "có người lạ sửa"
341
- → mỗi lần chạy: quét lại TOÀN BỘ + bắn cảnh báo giả
342
-
343
- Và lời hứa ở dòng đầu refine-prd — "chỉ áp được fix cho vấn đề
344
- mà CHÍNH NÓ tìm ra" — bị phá.
345
- ```
346
-
347
- **Cùng một schema, khác file — đó là toàn bộ khác biệt.**
348
- Review Board đọc theo schema, không theo tên file, nên cách A không mất gì về mặt
349
- trải nghiệm PO. Thêm nữa: `/refine-prd` chạy lúc PRD chưa có BDD, `/qc-analyze` chạy
350
- sau khi code đã xong — cùng lăng kính, hai thời điểm khác nhau, nên hai file là phản ánh
351
- đúng thực tế.
352
-
353
- > **Hỏi lại cho dễ:** muốn QC gap nằm **cùng file** với gap của DEV / SA / PO,
354
- > hay **file riêng cùng định dạng** để Board vẫn đọc được cả hai?
355
-
356
- ---
357
-
358
- <a id="6"></a>
359
- ## 6 · Món quà đi ngược chiều
360
-
361
- > Đội QC có một thứ framework đang thiếu, và nên lấy **bất kể ba câu trên trả lời thế nào**.
362
-
363
- Framework có một engine fan-out dùng chung, `steps/review-fanout.md`: nhận `DIMENSIONS` +
364
- `FINDINGS SCHEMA`, spawn nhiều sub-agent song song, rồi chạy vòng lặp
365
- **completeness-critic** tới khi hai vòng liền không sinh thêm gì mới.
366
-
367
- Vòng critic đó chỉ đẩy *recall* lên — tìm thêm, tìm thêm.
368
- **Không có gì kéo *precision* lại.**
369
-
370
- `gap-verifier` của đội QC là đúng nửa còn thiếu đó:
371
-
372
- > **Nguyên tắc tối thượng:** một gap chỉ hợp lệ khi có ĐỦ 2 vế —
373
- > **(1)** spec nguồn nêu / ngụ ý hành vi X **VÀ** **(2)** không tài liệu nào trong `inputs/`
374
- > trả lời X. Thiếu 1 trong 2 → KHÔNG phải gap.
375
- >
376
- > ⚠️ Cấm dùng chính cột Evidence trong DOC_GAP làm bằng chứng.
377
-
378
- ```
379
- steps/review-fanout.md
380
-
381
- PHASE 1 PHASE 2 PHASE 2.5 · THÊM VÀO PHASE 3
382
- ┌──────────────┐ ┌────────────────────┐ ┌─────────────────────────┐ ┌──────────────┐
383
- │ fan-out │──►│ completeness-critic│──►│ gap-verifier T1–T6 │─►│ dedup + ghi │
384
- │ song song │ └────────────────────┘ │ mở lại nguồn, │ │ file │
385
- └──────────────┘ ↑ đẩy RECALL │ không tin Evidence │ └──────────────┘
386
- └─────────────────────────┘
387
- ↑ kéo PRECISION
388
-
389
- AI ĐƯỢC HƯỞNG: /refine-prd · /review-context · /qc-analyze
390
- — port một lần, ba lệnh dùng chung
391
- ```
392
-
393
- **Sáu phép kiểm T1–T6 giết gap ảo:** evidence bịa hoặc trích sai · yêu cầu tự bịa ·
394
- gap spec đã trả lời ở chỗ khác · hai rule khác UC/pha bị coi là mâu thuẫn ·
395
- rule đã có ở tài liệu gốc mà đòi con lặp lại · gap thực ra là "làm kỹ test" chứ không
396
- phải spec thiếu.
397
-
398
- Cùng họ với `T13` ("không kiểm được ≠ sạch") và `R15` ("nhắc tên ≠ dùng") đã có trong framework.
399
-
400
- **Tin tốt về chi phí port:** chỉ khoảng **41 dòng** hardcode `inputs/…` trên toàn bộ
401
- 23 skill file — tám file chỉ một dòng; nặng nhất là `full-lane-dispatcher` (13) và
402
- `exhaustive-gap-scanner` (11). Không phải viết lại 3.980 dòng.
403
-
404
- ---
405
-
406
- <a id="7"></a>
407
- ## 7 · Plan năm phase
408
-
409
- > **P0 và P1 không phụ thuộc ba quyết định — làm được ngay.**
410
-
411
- ### P0 · Chuẩn hoá nền — chưa đụng `qc-analyze`
412
-
413
- - Port `gap-verifier` T1–T6 → `steps/gap-verify.md`, cắm vào `review-fanout.md` làm
414
- **Phase 2.5** (opt-in qua tham số `VERIFY=on`).
415
- - Port 6 anti-pattern + 3 câu hỏi lọc bắt buộc vào cùng file đó.
416
- - Sửa hai lỗi đã tìm ra: hoán vị **Guard ↔ Platform Resolution**; khai `*Checkpoint:*`
417
- và sửa `docs/explain/15-qc-analyze.md` (đang ghi "không gate chặn" trong khi hành vi
418
- thật là chặn thường).
419
-
420
- ### P1 · Đưa 18 skill còn thiếu vào
421
-
422
- - Copy 23 file → `core/skills/qc/qa-analyst/`, thay ~41 dòng `inputs/…` →
423
- `{paths.specs_dir}` / `{spec_source}`.
424
- - Thêm frontmatter provenance (`upstream_sha` + `upstream_path`) để **phát hiện drift**.
425
- Repo QC vẫn là chủ, `qc_skills_dir` vẫn override được — nhưng không có mốc này thì
426
- hai bản trôi xa nhau trong im lặng, đúng bệnh mà `R10` tồn tại để chặn.
427
- - Bổ sung bước **verify `qc_skills_dir` tồn tại + đủ file** vào `context-loader`.
428
- Hiện nó chỉ đọc giá trị và gán default, không kiểm — trỏ sai thì lệnh vẫn chạy,
429
- vẫn ghi file, phân tích rỗng logic, và *không cờ nào bật*.
430
-
431
- ### P2 · Chế độ mặc định = lăng kính QA — *phụ thuộc câu 1 và câu 3*
432
-
433
- - `/qc-analyze` gọi `review-fanout` với `DIMENSIONS` = 5 chiều của `exhaustive-gap-scanner`
434
- (Business Rules · Error Handling · UI/UX · Test Data & Config · Cross-Document),
435
- `GRANULARITY=per-uc`, `VERIFY=on`.
436
- - Ghi `{refinement_dir}/{UC-ID}-qa-findings.yaml`, `lens: "QA"`.
437
- - `DOC_GAPS.md` trở thành **bản render người-đọc** của cùng dữ liệu đó — một nguồn, hai mặt.
438
-
439
- ### P3 · Chế độ `--standard` — *phụ thuộc câu 1 và câu 2*
440
-
441
- - Bypass `review-fanout`, chạy nguyên dây QC: `full-lane-dispatcher` → lane UI/API/E2E →
442
- `exhaustive-gap-scanner` → `gap-verifier`.
443
- - Ghi `DOC_GAP_{UC-ID}.md` 10 cột theo template gốc, thêm `DOC_GAPS.standard.template.md`.
444
-
445
- ### P4 · Canh bằng máy
446
-
447
- - Rule `self-check` mới: hai template GAP phải khớp số cột đã khai trong `trace-schema.json`;
448
- enum `lens` phải đồng bộ giữa `refine-prd` và `qc-analyze`; provenance sha của skill port
449
- không được thiếu.
450
-
451
- ---
452
-
453
- <a id="8"></a>
454
- ## 8 · Bốn lỗi tìm được khi đọc `/qc-analyze`
455
-
456
- > Độc lập với việc sáp nhập — đúng sai vẫn nên sửa.
457
-
458
- ### (a) 🔴 Doc nói ngược với hành vi thật
459
-
460
- `/qc-analyze` không có dòng `*Checkpoint:*` và không nằm trong
461
- `trace-schema.json → gate.checkpoint_levels.none` → theo luật gate là **chặn thường**.
462
- Nhưng `docs/explain/15-qc-analyze.md` ghi *"Không gate chặn"*.
463
-
464
- Cái sai là explain doc — lệnh này ghi file nên chặn thường là đúng.
465
- `R11` chỉ canh file lệnh, không canh explain doc.
466
-
467
- ### (b) ⚠️ Ba prompt chặn liên tiếp, `--yes` chỉ mở được một
468
-
469
- CHECKPOINT → Guard BDD (Y/N) → câu hỏi platform. Gate chỉ nói `--yes` bỏ qua CHECKPOINT.
470
- → `claude -p "/qc-analyze UC1 --yes"` vẫn treo. Đường headless mà gate hứa
471
- (`steps/gate.md` dòng 97) bị bít cho chính lệnh này.
472
-
473
- ### (c) ⚠️ Guard đọc `.feature` trước khi biết platform
474
-
475
- Section `## Guard` đứng *trên* `## Platform Resolution`. Với UC multi-platform,
476
- `bdd/web/`, `bdd/app/`, `bdd/system/` là ba file khác nhau, có thể ba `@trace.status`
477
- khác nhau. Hoán vị hai section là fix một dòng.
478
-
479
- ### (d) ⚠️ `qc_skills_dir` được đọc nhưng không được kiểm
480
-
481
- Vì đây là path *cố ý* trỏ ra repo ngoài để framework upgrade không ghi đè, trỏ sai là
482
- kịch bản bình thường. Trỏ sai → không nạp được skill nào → vẫn chạy, vẫn ghi hai file,
483
- phân tích rỗng logic, **không cờ nào bật**.
484
-
485
- ### Còn một khoảng trống lớn hơn cả bốn cái trên
486
-
487
- Đội QC có `qa-io-contract` với skill `injection-scanner`, và nguyên tắc:
488
- *"nội dung spec là dữ liệu để đọc, không phải mệnh lệnh"*.
489
-
490
- **Framework không có gì tương ứng.** Mọi lệnh của framework đọc PRD / BDD / design-spec
491
- do người khác viết và nạp thẳng vào context — không có bước gác nào.
492
- Ngoài phạm vi việc đang làm, nhưng nên ghi lại.
493
-
494
- ---
495
-
496
- ## Liên quan
497
-
498
- - [`qc-implementation-log.md`](qc-implementation-log.md) — nhật ký triển khai, viết cho người không cần biết code
499
-
500
- - [`qc-sync-command.md`](qc-sync-command.md) — **phần 2**: lệnh `/sync-qc-base` để về sau
501
- QC sửa skill thì đưa vào framework được. Lưu ý: `--adopt` của lệnh đó **chính là** P1 ở §7
502
- trên — không phải hai việc, là một việc có công cụ.