@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.
- package/bin/qc-base-map.json +595 -0
- package/bin/self-check.js +146 -0
- package/core/FRAMEWORK_VERSION +1 -1
- package/core/commands/propose-scenario.md +1 -1
- package/core/commands/qc-analyze.md +398 -37
- package/core/commands/qc-design-test.md +141 -2
- package/core/commands/qc-plan.md +159 -10
- package/core/commands/qc-review.md +134 -1
- package/core/commands/qc-run-test.md +135 -2
- package/core/commands/refine-prd.md +47 -20
- package/core/commands/report-bug.md +1 -1
- package/core/commands/review-context.md +27 -1
- package/core/modules/qc-playwright/stack-profile.yaml +3 -3
- package/core/skills/qc/qa-analyst/DOC_GAP.template.md +147 -0
- package/core/skills/qc/qa-analyst/acceptance-criteria.md +5 -3
- package/core/skills/qc/qa-analyst/business-rules.md +39 -5
- package/core/skills/qc/qa-analyst/data-flow.md +6 -4
- package/core/skills/qc/qa-analyst/exhaustive-gap-scanner.md +174 -0
- package/core/skills/qc/qa-analyst/spec-breakdown.md +10 -8
- package/core/skills/qc/qa-analyst/spec-issue-reporter.md +112 -0
- package/core/skills/qc/qa-designer/e2e/journey.md +3 -3
- package/core/skills/qc/qa-designer/exploratory/charter.md +1 -1
- package/core/skills/qc/qa-designer/exploratory/explore-to-functional.md +2 -2
- package/core/skills/qc/qa-designer/functional/api.md +3 -3
- package/core/skills/qc/qa-designer/functional/gui-feature.md +3 -3
- package/core/skills/qc/qa-designer/functional/gui-screen.md +3 -3
- package/core/skills/qc/qa-designer/integration/api.md +3 -3
- package/core/skills/qc/qa-designer/integration/db.md +3 -3
- package/core/skills/qc/qa-designer/integration/gui.md +3 -3
- package/core/skills/qc/qa-designer/integration/kafka.md +3 -3
- package/core/skills/qc/qa-designer/non-functional.md +3 -3
- package/core/skills/qc/qa-planner/risk-model.md +106 -0
- package/core/skills/qc/qa-planner/test-plan.md +35 -21
- package/core/skills/qc/qa-reviewer/script/e2e.md +1 -1
- package/core/skills/qc/qa-reviewer/script/exploratory.md +1 -1
- package/core/skills/qc/qa-reviewer/script/functional.md +1 -1
- package/core/skills/qc/qa-reviewer/script/integration.md +1 -1
- package/core/skills/qc/qa-reviewer/script/non-functional.md +1 -1
- package/core/skills/qc/qa-reviewer/test-case/e2e.md +1 -1
- package/core/skills/qc/qa-reviewer/test-case/exploratory.md +1 -1
- package/core/skills/qc/qa-reviewer/test-case/functional.md +1 -1
- package/core/skills/qc/qa-reviewer/test-case/integration.md +2 -2
- package/core/skills/qc/qa-reviewer/test-case/non-functional.md +1 -1
- package/core/skills/qc/qa-runner/e2e.md +1 -1
- package/core/skills/qc/qa-runner/exploratory/session.md +2 -2
- package/core/skills/qc/qa-runner/functional/api.md +1 -1
- 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/skills/qc/qa-runner/integration.md +1 -1
- package/core/skills/qc/qa-runner/non-functional.md +1 -1
- package/core/skills/qc/qa-runner/report/report.md +1 -1
- package/core/steps/context-loader.md +1 -1
- package/core/steps/gap-verify.md +231 -0
- package/core/steps/qc-scope.md +119 -0
- package/core/steps/review-fanout.md +27 -1
- package/core/templates/project-context.yaml +5 -3
- package/docs/02-concepts/pipeline-steps/08-qc-automation.md +2 -2
- package/docs/04-reference/commands.md +1 -1
- package/docs/04-reference/configuration.md +146 -146
- package/docs/explain/03-refine-prd.md +8 -6
- package/docs/explain/15-qc-analyze.md +10 -7
- package/docs/explain/16-qc-plan.md +3 -3
- package/docs/explain/17-qc-design-test.md +1 -1
- package/docs/plans/qc-implementation-log.md +1587 -0
- package/docs/plans/qc-merge-plan.md +502 -0
- package/docs/plans/qc-sync-command.md +359 -0
- package/package.json +1 -1
- package/scripts/migrate-qc-docs.js +261 -0
- package/core/skills/qc/qa-analyst/DOC_GAPS.template.md +0 -63
|
@@ -162,7 +162,7 @@ Mỗi dòng ⚠️/🔴 phải ứng với một trạng thái **context-loader
|
|
|
162
162
|
🔴/⚠️ (không chặn ≠ không báo — người đọc log sau này vẫn cần thấy).
|
|
163
163
|
|
|
164
164
|
|
|
165
|
-
*Lưu ý: Với lệnh này, target ở Bước 1 là một UC-ID
|
|
165
|
+
*Lưu ý: Với lệnh này, target ở Bước 1 là một UC-ID (`active_platform` + `qc_artifact_dir` do §Phạm vi QC phân giải). `active_platform` này CHÍNH LÀ platform của sổ trace sẽ ghi `qc_status` (`{UC-ID}-{active_platform}.tsv`) — nên `@trace.verifies={UC-ID}-SC{N}` resolve không nhập nhằng. Đọc `.Test.md` đã review từ `{qc_artifact_dir}test-cases/`. Lệnh này dùng stack module **qc-playwright** (`.agent/modules/qc-playwright/stack-profile.yaml`) — Python + pytest-playwright + Page Object — độc lập với module implementation của dev.*
|
|
166
166
|
|
|
167
167
|
## Context
|
|
168
168
|
**BẮT BUỘC — đọc `.agent/steps/context-loader.md` và thực thi TOÀN BỘ quy trình trong đó**,
|
|
@@ -172,6 +172,139 @@ Bỏ qua bước này thì `{paths.*}`, `{tech_stack.*}`, `{conventions.*}`, gua
|
|
|
172
172
|
`project-lessons`, và routing service (chế độ umbrella) đều **chưa được phân giải** — mọi
|
|
173
173
|
placeholder bên dưới sẽ rỗng và lệnh sẽ đọc/ghi sai chỗ.
|
|
174
174
|
|
|
175
|
+
## Phạm vi QC
|
|
176
|
+
|
|
177
|
+
# QC Scope — phân giải phạm vi cho mọi lệnh `qc-*`
|
|
178
|
+
|
|
179
|
+
**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à
|
|
180
|
+
cả 6 trạm QC đều cần, để chúng không tự suy mỗi trạm một kiểu:
|
|
181
|
+
|
|
182
|
+
| Biến | Là gì |
|
|
183
|
+
|---|---|
|
|
184
|
+
| `TICKET-ID` | mã PRD — **thư mục artifact QC mang tên này** |
|
|
185
|
+
| `active_platform` | `web` \| `app` \| `system` \| … — một QC pass khoá đúng MỘT nền |
|
|
186
|
+
| `qc_artifact_dir` | `{paths.qc_dir}/{TICKET-ID}/{active_platform}/` |
|
|
187
|
+
| `uc_list` | các UC của (PRD × nền) này, kèm trạng thái BDD từng UC |
|
|
188
|
+
|
|
189
|
+
> **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ữ đã
|
|
190
|
+
> 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
|
|
191
|
+
> artifact vào sai thư mục **trong im lặng**.
|
|
192
|
+
|
|
193
|
+
---
|
|
194
|
+
|
|
195
|
+
## 1 — `TICKET-ID`
|
|
196
|
+
|
|
197
|
+
Artifact QC gom theo **PRD**, không theo UC. Nên mọi trạm phải quy được về `TICKET-ID`:
|
|
198
|
+
|
|
199
|
+
| `$ARGUMENTS` là | Cách lấy |
|
|
200
|
+
|---|---|
|
|
201
|
+
| **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 |
|
|
202
|
+
| **TICKET-ID** | dùng trực tiếp |
|
|
203
|
+
| 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 |
|
|
204
|
+
|
|
205
|
+
Đố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á
|
|
206
|
+
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.)
|
|
207
|
+
|
|
208
|
+
---
|
|
209
|
+
|
|
210
|
+
## 2 — `active_platform`
|
|
211
|
+
|
|
212
|
+
> **PHẢI phân giải TRƯỚC mọi phép đọc `.feature`.** `{UC-ID}-SC{N}` chỉ độc nhất trong
|
|
213
|
+
> (UC × nền), nên một UC đa nền có **nhiều file `.feature`** — `bdd/web/`, `bdd/app/`,
|
|
214
|
+
> `bdd/system/` — và mỗi file mang `@trace.status` **riêng**: bản web có thể `approved`
|
|
215
|
+
> 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
|
|
216
|
+
> 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
|
|
217
|
+
> một bản đã duyệt.
|
|
218
|
+
|
|
219
|
+
Theo thứ tự, dừng ở cái đầu tiên khớp:
|
|
220
|
+
|
|
221
|
+
1. `$ARGUMENTS` nêu nền (`web`/`app`/`system`/…) → dùng.
|
|
222
|
+
2. Target là một file `.feature` → đọc `# @trace.platform` của nó.
|
|
223
|
+
3. Glob `{paths.specs_dir}/{domain}/{prd-slug}/bdd/*/` — **đúng một** thư mục nền → dùng nó.
|
|
224
|
+
4. Glob `{paths.qc_dir}/{TICKET-ID}/*/` — **đúng một** thư mục nền đã có artifact → dùng nó.
|
|
225
|
+
*(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.)*
|
|
226
|
+
5. Nhiều nền mà không suy được → hỏi *"QC pass này cho nền nào? (web/app/system)"*.
|
|
227
|
+
**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
|
|
228
|
+
thư mục và ghi `qc_status` vào sai sổ trace:
|
|
229
|
+
```
|
|
230
|
+
❌ {TICKET-ID} có {n} nền ({list}) — không suy được nền nào cho QC pass này.
|
|
231
|
+
Chạy headless thì phải nêu tường minh: /{lệnh} {TICKET-ID} web --yes
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
Lưu `active_platform`. Từ đây, **mọi** phép đọc `.feature` chỉ đọc thư mục
|
|
235
|
+
`bdd/{active_platform}/` — không trộn SC chéo nền.
|
|
236
|
+
|
|
237
|
+
---
|
|
238
|
+
|
|
239
|
+
## 3 — `qc_artifact_dir`
|
|
240
|
+
|
|
241
|
+
```
|
|
242
|
+
qc_artifact_dir = {paths.qc_dir}/{TICKET-ID}/{active_platform}/
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
Chứa: `REQUIREMENT_ANALYSIS.md` · `DOC_GAP.md` · `TEST_PLAN.md` · `test-cases/*.Test.md`
|
|
246
|
+
— **mỗi loại đúng MỘT file cho cả PRD**, các UC là mục/hàng bên trong.
|
|
247
|
+
|
|
248
|
+
`{paths.qc_dir}` là folder top-level **nhìn thấy** trong repo QC (mặc định `docs/`, **không**
|
|
249
|
+
phải `.agent/` ẩn) để đội QC mở và xử lý output dễ dàng. Spec chính thức ở lại spec submodule
|
|
250
|
+
của PO — đừng ghi artifact QC vào đó.
|
|
251
|
+
|
|
252
|
+
> **Sổ trace KHÔNG theo layout này.** Nó vẫn là `{paths.trace_dir}/{domain}/{prd-slug}/{UC-ID}-{active_platform}.tsv`
|
|
253
|
+
> — 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
|
|
254
|
+
> **cột `UC`** của bảng gap, không qua đường dẫn file.
|
|
255
|
+
|
|
256
|
+
---
|
|
257
|
+
|
|
258
|
+
## 4 — `uc_list`
|
|
259
|
+
|
|
260
|
+
Glob `{paths.specs_dir}/{domain}/{prd-slug}/bdd/{active_platform}/*.feature`. Mỗi file → một
|
|
261
|
+
UC: đọc `# @trace.id` (mã UC) và `# @trace.status` từ header.
|
|
262
|
+
|
|
263
|
+
Chia hai nhóm:
|
|
264
|
+
|
|
265
|
+
| Nhóm | Điều kiện | Xử lý |
|
|
266
|
+
|---|---|---|
|
|
267
|
+
| **Trong phạm vi** | `@trace.status: approved` | phân tích / thiết kế / chạy bình thường |
|
|
268
|
+
| **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 |
|
|
269
|
+
|
|
270
|
+
In bảng phạm vi ra trước khi làm gì:
|
|
271
|
+
```
|
|
272
|
+
Phạm vi QC — {TICKET-ID} / {active_platform}
|
|
273
|
+
✅ {UC-ID} {tên UC} approved
|
|
274
|
+
⏸ {UC-ID} {tên UC} draft → chưa xét
|
|
275
|
+
→ {n} UC trong phạm vi · {m} chưa xét
|
|
276
|
+
```
|
|
277
|
+
|
|
278
|
+
**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
|
|
279
|
+
trong artifact là dựa trên BDD nháp.
|
|
280
|
+
|
|
281
|
+
**Không UC nào `approved` và không có `--include-draft` → DỪNG:**
|
|
282
|
+
```
|
|
283
|
+
❌ {TICKET-ID} ({active_platform}): 0/{n} UC có BDD approved — không có gì để chạy.
|
|
284
|
+
Cách đúng: người duyệt đặt `# @trace.status: approved` rồi chạy lại.
|
|
285
|
+
Muốn chạy sớm trên BDD nháp (prototype): thêm --include-draft
|
|
286
|
+
```
|
|
287
|
+
|
|
288
|
+
> **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
|
|
289
|
+
> **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à
|
|
290
|
+
> 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
|
|
291
|
+
> thường gặp là cái an toàn, và cái sớm phải nói ra.
|
|
292
|
+
|
|
293
|
+
> **Vì sao `--yes` không thay được `--include-draft`.** `--yes` nghĩa *"tôi không ngồi đây để
|
|
294
|
+
> 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
|
|
295
|
+
> 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.
|
|
296
|
+
|
|
297
|
+
|
|
298
|
+
> **Trạm này vẫn gọi theo TỪNG UC** *(B11)* — thiết kế và chạy test **thật sự** làm tăng dần
|
|
299
|
+
> theo UC, nên giữ khả năng làm UC1 khi UC3 chưa xong là đúng. Chỉ **chỗ đọc/ghi** đổi: mọi
|
|
300
|
+
> artifact nằm chung ở `{qc_artifact_dir}` cấp PRD, không còn một thư mục mỗi UC.
|
|
301
|
+
>
|
|
302
|
+
> Nên `DOC_GAP.md` / `TEST_PLAN.md` đọc được ở đây phủ **cả PRD**: **lọc theo cột `UC`** để lấy
|
|
303
|
+
> phần của UC đang làm. Đừng coi toàn bộ bảng gap là của UC này — sẽ chặn oan.
|
|
304
|
+
|
|
305
|
+
---
|
|
306
|
+
|
|
307
|
+
|
|
175
308
|
---
|
|
176
309
|
|
|
177
310
|
## Role & stack (theo module qc-playwright)
|
|
@@ -225,7 +358,7 @@ Sau khi chạy, cập nhật **sổ của platform đang test** `{paths.trace_di
|
|
|
225
358
|
| `qc_status` | Đọc cột `status` của row **TRƯỚC** — xem §Guard ngay dưới bảng. Row `OK`/`GAP`/`UNTRACKED`: `pass` nếu mọi QC test của SC này pass · `fail` nếu có cái fail · `skip` nếu tất cả skip/xfail · `not_run` nếu không QC test nào phủ nó. Row **`DRIFT`/`ORPHANED`**: **không bao giờ ghi `pass`** — hạ về `not_run` |
|
|
226
359
|
| `qc_run_at` | hôm nay `YYYY-MM-DD` |
|
|
227
360
|
| `last_updated` | hôm nay `YYYY-MM-DD` |
|
|
228
|
-
| `qc_owner` | **SC đang chờ ai** (view "pending" của PM/PO): `dev` nếu FAIL = product-gap (defect thật → dev fix) · `po` nếu `skip`/`not_run` vì một **`
|
|
361
|
+
| `qc_owner` | **SC đang chờ ai** (view "pending" của PM/PO): `dev` nếu FAIL = product-gap (defect thật → dev fix) · `po` nếu `skip`/`not_run` vì một **`DOC_GAP` 🔴 Blocker đang open** chặn test (PO phải làm rõ PRD/BDD) · `—` nếu `pass`, hoặc FAIL = script-bug (QC tự fix — tạm thời) |
|
|
229
362
|
| `qc_blocked_by` | artifact liên kết: `GAP-{id}` khi bị chặn bởi spec gap (set ở đây) · `BUG-{id}` khi `/report-bug` đã được file cho product-gap (backfill bởi `/report-bug`) · `—` ngược lại |
|
|
230
363
|
|
|
231
364
|
Set `qc_owner`/`qc_blocked_by` cùng với `qc_status`. Khi `pass`, **clear** cả hai về `—` — nhưng **PHẢI chạy §Đóng bug đã verify bên dưới TRƯỚC**, vì `qc_blocked_by` chính là con trỏ tới bug và clear xong là mất đường về.
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# /refine-prd — Phân tích PRD qua
|
|
1
|
+
# /refine-prd — Phân tích PRD qua 4 lăng kính review
|
|
2
2
|
|
|
3
3
|
> **Ranh giới — lệnh này chỉ áp được fix cho vấn đề mà CHÍNH NÓ tìm ra.** Resume Mode Phase 2 tự
|
|
4
4
|
> cấm đụng bất kỳ section nào không được một finding chấp nhận trỏ tới, và findings sinh từ việc soi
|
|
@@ -259,10 +259,11 @@ vòng không sinh thêm gì mới, *trước khi* ghi file findings.
|
|
|
259
259
|
|
|
260
260
|
Lệnh gọi cung cấp hai thứ bắt buộc + hai tuỳ chọn:
|
|
261
261
|
- **DIMENSIONS** — danh sách các chiều review để fan out
|
|
262
|
-
(`/refine-prd` →
|
|
262
|
+
(`/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).
|
|
263
263
|
- **FINDINGS SCHEMA** — dạng YAML mà mỗi finding phải theo (định nghĩa trong lệnh).
|
|
264
264
|
- **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.
|
|
265
265
|
- **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.
|
|
266
|
+
- **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.
|
|
266
267
|
|
|
267
268
|
> **Bỏ qua ở chế độ sub-agent:** Nếu Gate Bước 0 đã set `_agent_mode: true`, toàn bộ
|
|
268
269
|
> quy trình này bị **bỏ qua** — orchestrator đã chạy sẵn một dimension/UC cho mỗi
|
|
@@ -381,6 +382,31 @@ Ghi lại `convergence_rounds` (số vòng critic đã chạy) cho report.
|
|
|
381
382
|
|
|
382
383
|
---
|
|
383
384
|
|
|
385
|
+
## Phase 2.5 — Thẩm định *(chỉ chạy khi `VERIFY = on`)*
|
|
386
|
+
|
|
387
|
+
**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ề
|
|
388
|
+
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?"*.
|
|
389
|
+
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**
|
|
390
|
+
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 —
|
|
391
|
+
đú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
|
|
392
|
+
nhãn vấn đề cho thứ thực ra là chuyện làm-kỹ-hơn.
|
|
393
|
+
|
|
394
|
+
Chạy `steps/gap-verify.md` trên `ALL_FINDINGS` với:
|
|
395
|
+
- `FINDINGS` = `ALL_FINDINGS` (sau Phase 2)
|
|
396
|
+
- `EVIDENCE_ROOT` = `{paths.specs_dir}` — hoặc giá trị lệnh gọi chỉ định
|
|
397
|
+
- `VERDICT_FIELD` = trường trạng thái của FINDINGS SCHEMA mà lệnh định nghĩa
|
|
398
|
+
- `RERATE` = `on`
|
|
399
|
+
|
|
400
|
+
Finding bị `❌ INVALID` / `⚠️ RECLASSIFY` / `🔁 MERGE` **không đi tiếp sang Phase 3** — nhưng
|
|
401
|
+
**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
|
|
402
|
+
được vì sao chúng bị loại. Ghi lại số liệu verdict cho report.
|
|
403
|
+
|
|
404
|
+
> **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;
|
|
405
|
+
> 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ể
|
|
406
|
+
> "thắng" một finding thật ở bước giữ-cái-severity-cao-hơn.
|
|
407
|
+
|
|
408
|
+
---
|
|
409
|
+
|
|
384
410
|
## Phase 3 — Dedup, giải quyết xung đột, merge
|
|
385
411
|
|
|
386
412
|
Các sub-agent chạy **mù với nhau** (độc lập = độ phủ đa dạng). Chúng không bao giờ
|
|
@@ -412,7 +438,7 @@ Convergence: {convergence_rounds} vòng critic — file findings đã đầy đ
|
|
|
412
438
|
|
|
413
439
|
---
|
|
414
440
|
|
|
415
|
-
## Phân tích —
|
|
441
|
+
## Phân tích — 4 lăng kính (fan out cả bốn, rồi hội tụ)
|
|
416
442
|
|
|
417
443
|
Chạy review qua **Quy trình Review** ở trên (`steps/review-fanout.md`).
|
|
418
444
|
|
|
@@ -431,22 +457,23 @@ Chạy review qua **Quy trình Review** ở trên (`steps/review-fanout.md`).
|
|
|
431
457
|
- **`applied_to_version` có mặt VÀ `==` version PRD hiện tại** → PRD đổi đúng bằng phần lệnh này tự áp, không actor khác động vào → **DELTA**: `CHANGED_SCOPE` = { `uc_id`/`section` của các finding `status: applied` trong findings cũ } ∪ { UC có trong PRD hiện tại nhưng chưa từng xuất hiện ở findings cũ }. Truyền `CHANGED_SCOPE` này vào Quy trình Review.
|
|
432
458
|
- **`applied_to_version` vắng mặt HOẶC `≠` version hiện tại** → PRD đã bị sửa bởi **actor khác** (lệnh `/review-context`, sửa tay…) sau lần resume này → KHÔNG tin được phạm vi hẹp → **FULL** (KHÔNG truyền `CHANGED_SCOPE`), kèm cảnh báo: `"PRD đổi ngoài tầm theo dõi của findings (applied_to_version={A} ≠ hiện tại={C}); quét lại toàn bộ để khỏi sót UC do người/lệnh khác sửa."`
|
|
433
459
|
|
|
434
|
-
**DIMENSIONS** =
|
|
460
|
+
**DIMENSIONS** = 4 lăng kính dưới đây — fan out một sub-agent cho mỗi lăng kính, mỗi cái quét
|
|
435
461
|
toàn bộ PRD qua đúng lăng kính của nó:
|
|
436
462
|
|
|
437
|
-
|
|
438
|
-
LĂNG KÍNH BỊ TẮT (DISABLED — KHÔNG dùng, KHÔNG fan-out agent cho lăng kính này):
|
|
439
|
-
|
|
440
|
-
- **Lăng kính QA (tầng nghiệm thu)**: AC có nêu **outcome quan sát/kiểm được** chưa? — **KHÔNG** hỏi "AC đủ chi tiết chưa" (câu đó kéo cơ chế vào AC). Chi tiết cơ chế (số lần retry, timeout, tên/chủ cờ, nhánh lỗi vụn) thuộc **BR/BL**: nếu gap là cơ chế → suggestion phải **route sang BR/BL + AC ref**, KHÔNG phình AC. AC có lặp lại nội dung BR (trùng tầng) không → nếu có, đề xuất làm mỏng AC.
|
|
463
|
+
- **Lăng kính QA (tầng nghiệm thu)** *(bật lại 2026-08-25 — xem `docs/plans/qc-implementation-log.md` B8)*: AC có nêu **outcome quan sát/kiểm được** chưa? — **KHÔNG** hỏi "AC đủ chi tiết chưa" (câu đó kéo cơ chế vào AC). Chi tiết cơ chế (số lần retry, timeout, tên/chủ cờ, nhánh lỗi vụn) thuộc **BR/BL**: nếu gap là cơ chế → suggestion phải **route sang BR/BL + AC ref**, KHÔNG phình AC. AC có lặp lại nội dung BR (trùng tầng) không → nếu có, đề xuất làm mỏng AC.
|
|
441
464
|
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
465
|
+
> **Phạm vi lăng kính QA — hẹp có chủ ý, đừng nới.** Nó hỏi về **HÌNH THỨC** của AC (*"phát biểu này kiểm chứng được không?"* · *"có lặp tầng không?"*), **KHÔNG** về **NỘI DUNG** (*"còn thiếu gì?"*).
|
|
466
|
+
>
|
|
467
|
+
> Lý do là thời điểm: ở đây **chỉ có PRD** — design-spec, BDD, tech-doc đều chưa tồn tại. Nên không thể phân biệt *"PRD thiếu X"* với *"PRD cố ý để X cho design-spec"*, và phép kiểm *"đã trả lời ở tài liệu khác chưa?"* **không có tài liệu khác để tra**.
|
|
468
|
+
>
|
|
469
|
+
> Số liệu thật (14 lần chạy ở repo QC): review chỉ-đọc-PRD ra **14 gap** trung bình, review đủ 4 nguồn ra **9,4** — khoảng 5 gap chênh lệch là câu hỏi mà tài liệu sau **trả lời hộ**. Nới lăng kính này sang câu hỏi nội dung là cố tình sinh ra 5 gap đó rồi gửi PO.
|
|
470
|
+
>
|
|
471
|
+
> Câu hỏi nội dung thuộc `/qc-analyze` (3 lăng kính: xử lý lỗi · giao diện · dữ liệu & cấu hình), nơi đã có đủ 4 nguồn để tra.
|
|
472
|
+
>
|
|
473
|
+
> **CÁCH TẮT LẠI QA** *(nếu cần)*: gỡ bullet QA ở trên · đổi `4 lăng kính`/`cả bốn` → `3`/`cả ba` ở
|
|
474
|
+
> dòng tiêu đề, heading `## Phân tích`, câu `DIMENSIONS = N lăng kính`, và `steps/review-fanout.md` ·
|
|
475
|
+
> gỡ `QA` khỏi enum `lens:` + `by_lens` + ghi chú `phán đoán QA/DEV/SA/PO` · sửa
|
|
476
|
+
> `docs/explain/03-refine-prd.md` cho khớp · rebuild `node bin/build.js`.
|
|
450
477
|
|
|
451
478
|
> **Nguyên tắc chung cho DEV & SA — đọc bằng mắt kỹ thuật, VIẾT bằng lời nghiệp vụ.**
|
|
452
479
|
> Hai lăng kính này dùng con mắt kỹ thuật để **phát hiện chỗ nghiệp vụ mô tả thiếu/mơ hồ/mâu thuẫn đến mức sẽ chặn triển khai** — mục tiêu là **làm rõ vấn đề nghiệp vụ để sau này xử lý được về mặt kỹ thuật**. **KHÔNG** đưa góc nhìn kỹ thuật vào PRD, **KHÔNG** đề xuất giải pháp/cơ chế kỹ thuật. Mọi `finding` và `suggestion` phải **thuần nghiệp vụ** (tuân Business Language Guard): mô tả *cái nghiệp vụ còn thiếu/chưa rõ* và *hỏi cần làm rõ gì*, chứ không nói *làm thế nào về kỹ thuật*.
|
|
@@ -483,7 +510,7 @@ status: "pending_review"
|
|
|
483
510
|
|
|
484
511
|
findings:
|
|
485
512
|
- id: "F001"
|
|
486
|
-
lens: "DEV" # DEV | SA | PO
|
|
513
|
+
lens: "DEV" # QA | DEV | SA | PO
|
|
487
514
|
severity: "major" # critical | major | minor
|
|
488
515
|
section: "§2. Acceptance Criteria" # nhãn heading/section dạng người đọc
|
|
489
516
|
uc_id: "{TICKET-ID}-UC{N}" # UC mà finding thuộc về; "" nếu PRD-global (scope, metrics, problem statement)
|
|
@@ -499,8 +526,8 @@ findings:
|
|
|
499
526
|
# true = AI tự tin cao vào suggestion này; Review Board có thể hiển thị nút "quick accept"
|
|
500
527
|
# false = cần human đọc kỹ và ghi quyết định trước khi accept
|
|
501
528
|
# Resume Mode luôn áp dụng theo status (accepted|modified), bất kể auto_fixable.
|
|
502
|
-
# LƯU Ý: /refine-prd CỐ Ý không có `--fix` mode (khác /review-context) — finding
|
|
503
|
-
# là phán đoán DEV/SA/PO, phải qua người duyệt ở Board; auto_fixable ở đây CHỈ là gợi ý
|
|
529
|
+
# LƯU Ý: /refine-prd CỐ Ý không có `--fix` mode (khác /review-context) — finding 4 lăng kính
|
|
530
|
+
# là phán đoán QA/DEV/SA/PO, phải qua người duyệt ở Board; auto_fixable ở đây CHỈ là gợi ý
|
|
504
531
|
# quick-accept cho Board, KHÔNG để máy tự áp.
|
|
505
532
|
status: "pending"
|
|
506
533
|
applied_via: ""
|
|
@@ -516,7 +543,7 @@ findings:
|
|
|
516
543
|
summary:
|
|
517
544
|
total_findings: {N}
|
|
518
545
|
by_severity: { critical: {N}, major: {N}, minor: {N} }
|
|
519
|
-
by_lens: { DEV: {N}, SA: {N}, PO: {N} }
|
|
546
|
+
by_lens: { QA: {N}, DEV: {N}, SA: {N}, PO: {N} }
|
|
520
547
|
recommendation: "APPROVED_WITH_MINOR_CHANGES | NEEDS_REVISION | BLOCKED"
|
|
521
548
|
# Rule: critical ≥ 1 → BLOCKED
|
|
522
549
|
# critical = 0, major ≥ 1 → NEEDS_REVISION
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# /report-bug — File một Bug có trace-spec (cho Tester & QC)
|
|
2
2
|
|
|
3
3
|
Dành cho **tester và QC** — gồm cả **product-gap** lòi ra từ pipeline `/qc-*`
|
|
4
|
-
(`/qc-run-test` FAIL phân loại product-gap, hoặc một spec-defect blocker `
|
|
4
|
+
(`/qc-run-test` FAIL phân loại product-gap, hoặc một spec-defect blocker `DOC_GAP` từ
|
|
5
5
|
`/qc-analyze`). Sinh một bug report có cấu trúc với đầy đủ spec context, phân loại layer
|
|
6
6
|
khả nghi, và lưu lại để handoff cho team dev.
|
|
7
7
|
|
|
@@ -267,10 +267,11 @@ vòng không sinh thêm gì mới, *trước khi* ghi file findings.
|
|
|
267
267
|
|
|
268
268
|
Lệnh gọi cung cấp hai thứ bắt buộc + hai tuỳ chọn:
|
|
269
269
|
- **DIMENSIONS** — danh sách các chiều review để fan out
|
|
270
|
-
(`/refine-prd` →
|
|
270
|
+
(`/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).
|
|
271
271
|
- **FINDINGS SCHEMA** — dạng YAML mà mỗi finding phải theo (định nghĩa trong lệnh).
|
|
272
272
|
- **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.
|
|
273
273
|
- **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.
|
|
274
|
+
- **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.
|
|
274
275
|
|
|
275
276
|
> **Bỏ qua ở chế độ sub-agent:** Nếu Gate Bước 0 đã set `_agent_mode: true`, toàn bộ
|
|
276
277
|
> quy trình này bị **bỏ qua** — orchestrator đã chạy sẵn một dimension/UC cho mỗi
|
|
@@ -389,6 +390,31 @@ Ghi lại `convergence_rounds` (số vòng critic đã chạy) cho report.
|
|
|
389
390
|
|
|
390
391
|
---
|
|
391
392
|
|
|
393
|
+
## Phase 2.5 — Thẩm định *(chỉ chạy khi `VERIFY = on`)*
|
|
394
|
+
|
|
395
|
+
**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ề
|
|
396
|
+
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?"*.
|
|
397
|
+
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**
|
|
398
|
+
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 —
|
|
399
|
+
đú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
|
|
400
|
+
nhãn vấn đề cho thứ thực ra là chuyện làm-kỹ-hơn.
|
|
401
|
+
|
|
402
|
+
Chạy `steps/gap-verify.md` trên `ALL_FINDINGS` với:
|
|
403
|
+
- `FINDINGS` = `ALL_FINDINGS` (sau Phase 2)
|
|
404
|
+
- `EVIDENCE_ROOT` = `{paths.specs_dir}` — hoặc giá trị lệnh gọi chỉ định
|
|
405
|
+
- `VERDICT_FIELD` = trường trạng thái của FINDINGS SCHEMA mà lệnh định nghĩa
|
|
406
|
+
- `RERATE` = `on`
|
|
407
|
+
|
|
408
|
+
Finding bị `❌ INVALID` / `⚠️ RECLASSIFY` / `🔁 MERGE` **không đi tiếp sang Phase 3** — nhưng
|
|
409
|
+
**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
|
|
410
|
+
được vì sao chúng bị loại. Ghi lại số liệu verdict cho report.
|
|
411
|
+
|
|
412
|
+
> **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;
|
|
413
|
+
> 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ể
|
|
414
|
+
> "thắng" một finding thật ở bước giữ-cái-severity-cao-hơn.
|
|
415
|
+
|
|
416
|
+
---
|
|
417
|
+
|
|
392
418
|
## Phase 3 — Dedup, giải quyết xung đột, merge
|
|
393
419
|
|
|
394
420
|
Các sub-agent chạy **mù với nhau** (độc lập = độ phủ đa dạng). Chúng không bao giờ
|
|
@@ -19,11 +19,11 @@ architecture:
|
|
|
19
19
|
- "Each test independent via pytest-playwright fixtures (page / logged_in_page / …)"
|
|
20
20
|
- "Page Object extends slim BasePage; split 3 layers: locators _x(), actions verb_noun(), assertions assert_x() using expect()"
|
|
21
21
|
- "Locator priority: data-testid → role → label/text → CSS → avoid XPath"
|
|
22
|
-
- "test-id values come from the FE tech-design §2b Test Selectors contract ({
|
|
22
|
+
- "test-id values come from the FE tech-design §2b Test Selectors contract (tech-doc gộp cấp PRD: {TICKET-ID}-tech-design.md, bảng Test Selectors §4.5.6 — lọc theo cột "Serves SC") — prefer them (no runtime scan); fall back to role/text only when an actionable element has no test-id there, and note the gap"
|
|
23
23
|
- "Group tests by (role, account) so login/logout never interleaves across roles"
|
|
24
24
|
- "Cover 100% of TCs in the .Test.md — every TC ends Pass/Fail/Skip, none left Draft"
|
|
25
25
|
folder_structure: |
|
|
26
|
-
{
|
|
26
|
+
{qc_artifact_dir}test-cases/ ← test-case Markdown (.Test.md) — source of truth (mặc định docs/, lộ ra ngoài)
|
|
27
27
|
pages/ ← Page Object Model
|
|
28
28
|
│ ├── base_page.py ← slim BasePage (click/fill/wait/screenshot)
|
|
29
29
|
│ └── <feature>_page.py
|
|
@@ -42,7 +42,7 @@ coding_standards:
|
|
|
42
42
|
test_function: "test_TC<NNN>_<snake_case>"
|
|
43
43
|
page_object: "<feature>_page.py with <Feature>Page class extending BasePage"
|
|
44
44
|
files:
|
|
45
|
-
test_case_md: "{
|
|
45
|
+
test_case_md: "{qc_artifact_dir}test-cases/TC_<FEATURE>.Test.md"
|
|
46
46
|
page_object: "pages/<feature>_page.py"
|
|
47
47
|
test_script: "tests/<project>/test_<feature>.py"
|
|
48
48
|
patterns:
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
---
|
|
2
|
+
version: 1.0
|
|
3
|
+
updated: 2026-08-25
|
|
4
|
+
ported_from: ui-automation-testing
|
|
5
|
+
upstream_path: skills/qa-tc-analyst/spec-issue-reporter/DOC_GAPS.template.md
|
|
6
|
+
upstream_sha: c7ca6cfb798c609f18ffe20a38f64f95c76e1919
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
> **Template DUY NHẤT cho file gap của `/qc-analyze`** *(B9 — hợp nhất 2026-08-25)*.
|
|
10
|
+
> Bản 9 cột cũ đã bỏ: nó thiếu đúng hai thứ PO cần — cột *Giao cho đội* và ô câu hỏi 4 phần.
|
|
11
|
+
> Giữ một bản kém hơn làm mặc định là để người không biết có cờ nhận bản kém.
|
|
12
|
+
>
|
|
13
|
+
> **Một chỗ CỐ Ý khác upstream:** mức nặng nhất dùng từ **`Blocker`**, không phải `Critical`.
|
|
14
|
+
> Lý do: `/qc-run-test` đọc `🔴 Blocker` để đặt *"scenario đang chờ PO"* vào sổ kết quả trace.
|
|
15
|
+
> Đổi từ là đứt liên kết đó. Ba mức còn lại giữ nguyên upstream.
|
|
16
|
+
>
|
|
17
|
+
> **Phạm vi: MỘT file cho cả (PRD × nền)** *(B11)*, không phải một file mỗi UC. Đây là quay về
|
|
18
|
+
> đúng thiết kế upstream — chính ID `GAP-<UC>-…` của bản gốc chỉ có nghĩa khi một file chứa
|
|
19
|
+
> nhiều UC, và file thật của đội QC (`DOC_GAP_FEAT-02-3.md`) cũng không có hậu tố UC. Đường
|
|
20
|
+
> dẫn: `{paths.qc_dir}/{TICKET-ID}/{platform}/DOC_GAP.md`.
|
|
21
|
+
|
|
22
|
+
# DOC GAP -- <TICKET-ID> / <nền>: <Tên feature>
|
|
23
|
+
|
|
24
|
+
| Trường | Giá trị |
|
|
25
|
+
|---|---|
|
|
26
|
+
| Feature | `<TICKET-ID>` — `<Tên feature>` |
|
|
27
|
+
| Nền (platform) | `<web \| app \| system>` |
|
|
28
|
+
| Tài liệu nguồn | `<đường dẫn PRD>` · `<đường dẫn BDD nếu có>` · `<các file inputs/ liên quan>` |
|
|
29
|
+
| Ngày phân tích | `<YYYY-MM-DD>` |
|
|
30
|
+
| Tổng số gap | `<N>` (Blocker: x · High: y · Medium: z · Low: w) |
|
|
31
|
+
| Trạng thái chung | 🔴 Blocked / 🟠 Cần làm rõ / 🟢 Đủ rõ để thiết kế TC |
|
|
32
|
+
|
|
33
|
+
---
|
|
34
|
+
|
|
35
|
+
## Phạm vi phân tích
|
|
36
|
+
|
|
37
|
+
> **Một file gap phủ CẢ PRD** — mỗi UC là các hàng trong bảng gap, phân biệt bằng cột `UC`.
|
|
38
|
+
> Bảng dưới là **căn cứ độ phủ**: nó phân biệt *"đã xét, không thấy gap"* với *"chưa xét"*.
|
|
39
|
+
> UC nào có BDD chưa `approved` thì ghi `⏸ Chưa xét` — **KHÔNG bỏ khỏi bảng**.
|
|
40
|
+
|
|
41
|
+
| UC | Tên UC | `@trace.status` | Đã phân tích? | Số gap |
|
|
42
|
+
|---|---|---|---|---|
|
|
43
|
+
| `<UC-ID>` | … | `approved` | ✅ | `<n>` |
|
|
44
|
+
| `<UC-ID>` | … | `draft` | `⏸ Chưa xét` | — |
|
|
45
|
+
|
|
46
|
+
**Trong phạm vi: `<n>`/`<N>` UC.** Chưa xét: `<danh sách UC-ID>` — chạy lại sau khi BDD được duyệt, hoặc `--include-draft` để xét luôn bản nháp.
|
|
47
|
+
|
|
48
|
+
---
|
|
49
|
+
|
|
50
|
+
## Tài liệu đầu vào đã đọc để phân tích
|
|
51
|
+
|
|
52
|
+
> Liệt kê **đầy đủ** mọi file đã đọc để dựng phân tích gap (spec chính + mọi ref-link + transitive 1-hop). Đây là căn cứ độ phủ — mọi file đã mở đều phải có mặt, KHÔNG bỏ sót. Đường dẫn tính từ `{paths.specs_dir}`.
|
|
53
|
+
|
|
54
|
+
| # | Đường dẫn (từ `{paths.specs_dir}`) | Vai trò | Phiên bản |
|
|
55
|
+
|---|---|---|---|
|
|
56
|
+
| 1 | `<đường dẫn spec chính>` | **Spec chính** | `<vX.Y>` |
|
|
57
|
+
| 2 | `<đường dẫn ref>` | Ref bắt buộc — `<lý do>` | `—` |
|
|
58
|
+
| ... | ... | Transitive 1-hop — `<feature liền kề / dịch vụ tiêu thụ>` | `—` |
|
|
59
|
+
|
|
60
|
+
**Tổng: `<N>` tài liệu.** Lane API: `<có → liệt kê openapi.yaml/*.dbml/tdd | không có → SKIP, không đọc, không bịa endpoint>` *(chỉ áp khi framework đã nhận trục lane — xem B5)*. Không dùng làm evidence: Change log · Appendix · mục Giả định AI.
|
|
61
|
+
|
|
62
|
+
---
|
|
63
|
+
|
|
64
|
+
> **ID gap mang UC** — `GAP-UC{N}-{nnn}` (vd `GAP-UC1-001`). Gap thuộc **cả PRD**, không riêng
|
|
65
|
+
> UC nào → `GAP-GEN-{nnn}`. Đánh số **độc lập trong từng UC**: chạy lại phân tích cho UC1
|
|
66
|
+
> KHÔNG được làm đổi số gap của UC2 — test case đã có đang trỏ `🚫 Block: [GAP-UC2-003]`, đổi
|
|
67
|
+
> số là đứt liên kết đó trong im lặng.
|
|
68
|
+
|
|
69
|
+
| ID | UC | Loại | Vấn đề cần confirm | Câu hỏi / Lý do cần confirm & Gợi ý | Trích đoạn tài liệu (Evidence) | Giao cho đội | Mức độ | Người trả lời | Trạng thái | Câu trả lời |
|
|
70
|
+
|---|---|---|---|---|---|---|---|---|---|---|
|
|
71
|
+
| GAP-UC1-001 | `<UC-ID>` | MISSING / AMBIGUOUS / CONTRADICTORY / ASSUMPTION | Tiêu đề ngắn mô tả vấn đề | **Bối cảnh:** Ngữ cảnh dẫn đến gap này.<br/>**Vấn đề:** Điều gì chưa được spec hoặc mâu thuẫn.<br/>**Tại sao quan trọng:** Hậu quả nếu không làm rõ.<br/>**Gợi ý:** Ai cần làm gì để giải quyết. | `<đường dẫn file spec>` `<TÊN-BR hoặc AC gốc trong PRD, ví dụ FEAT-01-2-UC4-BR11>`: trích nguyên văn | Dev / PO / BA / Design | 🔴 Blocker | | Open | |
|
|
72
|
+
|
|
73
|
+
---
|
|
74
|
+
|
|
75
|
+
## Ưu tiên xử lý
|
|
76
|
+
|
|
77
|
+
| Mức độ | Gap ID |
|
|
78
|
+
|---|---|
|
|
79
|
+
| 🔴 Blocker | GAP-UC1-00x · GAP-UC3-00x · ... |
|
|
80
|
+
| 🟠 High | GAP-UC2-00x · ... |
|
|
81
|
+
| 🟡 Medium | GAP-UC1-00x · ... |
|
|
82
|
+
| ⚪ Low | GAP-GEN-00x · ... |
|
|
83
|
+
|
|
84
|
+
*Xếp theo mức độ trước, KHÔNG theo UC — người đọc cần biết "chặn gì" trước "chặn ở đâu".*
|
|
85
|
+
|
|
86
|
+
**Cần chốt trước khi viết test case:**
|
|
87
|
+
- GAP-UC1-00x (`<UC-ID>`): <lý do block>
|
|
88
|
+
|
|
89
|
+
---
|
|
90
|
+
|
|
91
|
+
## Chú thích (Legend)
|
|
92
|
+
|
|
93
|
+
### Loại Gap
|
|
94
|
+
|
|
95
|
+
| Loại | Mô tả |
|
|
96
|
+
|---|---|
|
|
97
|
+
| MISSING | Thông tin, chức năng, quy tắc, hoặc kịch bản chưa được mô tả trong bất kỳ tài liệu nào trong `{paths.specs_dir}`. |
|
|
98
|
+
| AMBIGUOUS | Mô tả mơ hồ, có thể hiểu theo nhiều cách, hoặc thiếu chi tiết để viết kịch bản kiểm thử. |
|
|
99
|
+
| CONTRADICTORY | Hai hoặc nhiều tài liệu trong `{paths.specs_dir}` mô tả cùng một hành vi nhưng mâu thuẫn nhau. |
|
|
100
|
+
| ASSUMPTION | Giả định do nhóm QA tự suy luận từ tài liệu trong `{paths.specs_dir}`, chưa được PO/Dev xác nhận tường minh. |
|
|
101
|
+
|
|
102
|
+
### Mức độ
|
|
103
|
+
|
|
104
|
+
| Mức | Ý nghĩa |
|
|
105
|
+
|---|---|
|
|
106
|
+
| 🔴 Blocker | Chặn viết kịch bản kiểm thử hoặc lập trình — không thể tiến hành nếu chưa có câu trả lời. |
|
|
107
|
+
| 🟠 High | Ảnh hưởng đến nhiều kịch bản kiểm thử hoặc logic nghiệp vụ chính — cần giải quyết trước khi viết test case. |
|
|
108
|
+
| 🟡 Medium | Ảnh hưởng đến một số kịch bản cụ thể — cần giải quyết trước sprint kiểm thử. |
|
|
109
|
+
| ⚪ Low | Ít ảnh hưởng — có thể ghi giả định tạm thời và xử lý trong sprint review. |
|
|
110
|
+
|
|
111
|
+
### Giao cho đội
|
|
112
|
+
|
|
113
|
+
| Ký hiệu | Đội |
|
|
114
|
+
|---|---|
|
|
115
|
+
| Dev | Đội phát triển (Frontend + Backend) |
|
|
116
|
+
| Architect | Kiến trúc sư hệ thống |
|
|
117
|
+
| PO | Product Owner |
|
|
118
|
+
| BA | Business Analyst |
|
|
119
|
+
| Design | Đội thiết kế UX/UI |
|
|
120
|
+
| Analytics | Nhóm dữ liệu / phân tích |
|
|
121
|
+
|
|
122
|
+
---
|
|
123
|
+
|
|
124
|
+
## ⚠️ Checklist bắt buộc trước khi lưu file
|
|
125
|
+
|
|
126
|
+
Trước khi lưu file gap, kiểm tra **từng hàng** trong bảng gap:
|
|
127
|
+
|
|
128
|
+
- [ ] **Có section `Tài liệu đầu vào đã đọc để phân tích`** – bảng liệt kê **đầy đủ** mọi file đã đọc (spec chính + ref-link + transitive 1-hop), có đường dẫn `{paths.specs_dir}`, vai trò, phiên bản; ghi tổng số + trạng thái lane API. KHÔNG bỏ sót file nào đã mở.
|
|
129
|
+
- [ ] **Có section `Phạm vi phân tích`** – bảng mỗi UC một hàng kèm `@trace.status` + Đã phân tích? + Số gap. UC chưa duyệt vẫn có hàng, ghi `⏸ Chưa xét`. Thiếu bảng này thì không ai phân biệt được *"đã xét, không thấy gap"* với *"chưa xét"*.
|
|
130
|
+
- [ ] **11 cột đủ** – đúng thứ tự: `ID | UC | Loại | Vấn đề cần confirm | Câu hỏi / Lý do cần confirm & Gợi ý | Trích đoạn tài liệu (Evidence) | Giao cho đội | Mức độ | Người trả lời | Trạng thái | Câu trả lời`
|
|
131
|
+
- [ ] **Cột 2 = `UC`** – mã UC đầy đủ (`<TICKET-ID>-UC{N}`), hoặc `— (toàn PRD)` cho gap `GAP-GEN-`. Mọi UC có gap phải khớp một hàng `✅` ở bảng *Phạm vi phân tích*.
|
|
132
|
+
- [ ] **ID dạng `GAP-UC{N}-{nnn}`** (hoặc `GAP-GEN-{nnn}`) – KHÔNG dùng `GAP-01` phẳng: số phẳng sẽ bị đánh lại khi phân tích lại một UC, làm đứt `🚫 Block: [GAP-xx]` trong test case đã có.
|
|
133
|
+
- [ ] **Cột 4 = `Vấn đề cần confirm`** – KHÔNG viết tắt thành `Vấn đề`
|
|
134
|
+
- [ ] **Cột 5 = `Câu hỏi / Lý do cần confirm & Gợi ý`** – bắt buộc có đủ 4 phần, tách bằng `<br/>`:
|
|
135
|
+
```
|
|
136
|
+
**Bối cảnh:** ...<br/>**Vấn đề:** ...<br/>**Tại sao quan trọng:** ...<br/>**Gợi ý:** ...
|
|
137
|
+
```
|
|
138
|
+
Không viết 4 mục liên tiếp trên cùng một dòng.
|
|
139
|
+
- [ ] **Cột 6 = `Trích đoạn tài liệu (Evidence)`** – KHÔNG viết tắt thành `Evidence`; dẫn nguyên văn + đường dẫn file `{paths.specs_dir}`; **dùng PRD source ID** (ví dụ `FEAT-01-2-UC4-BR11`), KHÔNG dùng internal analysis ID (ví dụ `BR-UC4-12`)
|
|
140
|
+
- [ ] **Cột Mức độ** (cột 8) – bắt buộc dùng emoji: `🔴 Blocker` / `🟠 High` / `🟡 Medium` / `⚪ Low`. Không được ghi text thuần.
|
|
141
|
+
- [ ] **Cột Giao cho đội** (cột 7) – dùng: `Dev` / `PO` / `BA` / `Design` / `Architect` / `Analytics` hoặc kết hợp. Nếu thấy "Open" ở đây → đang bị lệch cột.
|
|
142
|
+
- [ ] **Cột Người trả lời = vai trò** (PO / BA / Dev / Design / ...). Nếu thấy "Open" ở đây → đang bị lệch cột.
|
|
143
|
+
- [ ] **Cột Trạng thái** = `Open` / `Resolved` / `Out of Scope` / `Re-scoped → Covered`
|
|
144
|
+
- [ ] **Trạng thái chung** trong metadata có emoji: `🔴 Blocked` / `🟠 Cần làm rõ` / `🟢 Đủ rõ để thiết kế TC`
|
|
145
|
+
- [ ] **Có đủ 3 section cuối**: Ưu tiên xử lý · Chú thích (Legend) với bảng đầy đủ
|
|
146
|
+
- [ ] **KHÔNG có section "Change log"** và **KHÔNG có section "AI Assumptions"**
|
|
147
|
+
- [ ] **Evidence chỉ từ `{paths.specs_dir}`** – không dùng file trong `{paths.qc_dir}` nội bộ (TC_*.md, REQUIREMENT_ANALYSIS*.md, DOC_GAP*.md khác)
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
---
|
|
2
2
|
version: 1.0
|
|
3
3
|
updated: 2026-06-11
|
|
4
|
-
ported_from:
|
|
4
|
+
ported_from: ui-automation-testing
|
|
5
|
+
upstream_path: skills/qa-tc-analyst/acceptance-criteria.md
|
|
6
|
+
upstream_sha: 516f35cf78102d27aa5639bfb2818274399800c0
|
|
5
7
|
---
|
|
6
8
|
|
|
7
9
|
# Acceptance Criteria — Sinh tiêu chí chấp nhận
|
|
@@ -51,8 +53,8 @@ Mỗi AC gắn mã trace: chức năng + BR-xx để TC sau này map 1-1.
|
|
|
51
53
|
|
|
52
54
|
## Output
|
|
53
55
|
|
|
54
|
-
Ghi vào **mục Acceptance Criteria** của `{
|
|
55
|
-
(KHÔNG tạo file riêng — qc-analyze chỉ trả 2 file: `REQUIREMENT_ANALYSIS.md` + `
|
|
56
|
+
Ghi vào **mục Acceptance Criteria** của `{qc_artifact_dir}REQUIREMENT_ANALYSIS.md`
|
|
57
|
+
(KHÔNG tạo file riêng — qc-analyze chỉ trả 2 file: `REQUIREMENT_ANALYSIS.md` + `DOC_GAP.md`):
|
|
56
58
|
|
|
57
59
|
- Danh sách AC dạng Given/When/Then, có mã trace về chức năng, business rule (BR-xx)
|
|
58
60
|
và scenario chính thức `{UC-ID}-SC{N}` của `.feature`.
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
---
|
|
2
2
|
version: 1.0
|
|
3
|
-
updated: 2026-
|
|
4
|
-
ported_from:
|
|
3
|
+
updated: 2026-08-25
|
|
4
|
+
ported_from: ui-automation-testing
|
|
5
|
+
upstream_path: skills/qa-tc-analyst/business-rules.md
|
|
6
|
+
upstream_sha: 0d5f01257c30182d1c98835303640775d360a3da
|
|
5
7
|
---
|
|
6
8
|
|
|
7
9
|
# Business Rules — Trích xuất luật nghiệp vụ
|
|
@@ -25,6 +27,38 @@ Trích xuất và liệt kê toàn bộ business rule, điều kiện và ràng
|
|
|
25
27
|
1. Đọc spec đã bóc tách (output của spec-breakdown) hoặc tài liệu gốc.
|
|
26
28
|
2. Quét tìm: điều kiện ("nếu… thì…"), ràng buộc field, giới hạn (min/max, rate limit),
|
|
27
29
|
quy tắc phân quyền, công thức tính, quy tắc trạng thái, default value.
|
|
30
|
+
3. **Checklist ràng buộc field — kiểm tra TẤT CẢ field (kể cả tuỳ chọn / optional):**
|
|
31
|
+
- [ ] `minlength` / `maxlength` — PRD có nêu không? Nếu không → GAP (MISSING)
|
|
32
|
+
- [ ] Ký tự được phép — chữ, số, tiếng Việt có dấu, ký tự đặc biệt, khoảng trắng?
|
|
33
|
+
- [ ] Trim khoảng trắng đầu/cuối — có hay không?
|
|
34
|
+
- [ ] Format đặc biệt — email, SĐT, ngày tháng, v.v.
|
|
35
|
+
> ⚠️ **Field tuỳ chọn (optional) vẫn phải kiểm tra đủ 4 mục trên.** "Không bắt buộc nhập" KHÔNG đồng nghĩa với "không có ràng buộc". Đây là nguồn gốc hay bị bỏ sót khi phân tích.
|
|
36
|
+
|
|
37
|
+
4. **Checklist đặc biệt — hay bị bỏ sót khi đọc BDD/PRD:**
|
|
38
|
+
|
|
39
|
+
**a. Routing table — đọc cả 2 chiều:**
|
|
40
|
+
- [ ] Với MỖI rule "nếu đủ điều kiện → bỏ qua / nếu thiếu → vào": đánh dấu cả 2 nhánh cần test
|
|
41
|
+
- [ ] Routing table N loại tài khoản × M màn → duyệt từng ô, không bỏ dòng nào
|
|
42
|
+
|
|
43
|
+
**b. Liệt kê hết variant:**
|
|
44
|
+
- [ ] Spec đề cập nhiều provider/platform/giá trị liệt kê (Google/Facebook, Lớp 1-6...)? → ghi từng variant ra
|
|
45
|
+
- [ ] Với mỗi variant: behavior hoặc content có khác nhau không? Nếu có → đánh dấu cần TC riêng
|
|
46
|
+
|
|
47
|
+
**c. Telemetry/event analytics:**
|
|
48
|
+
- [ ] Liệt kê TẤT CẢ event name được nhắc trong BDD/PRD cho UC này
|
|
49
|
+
- [ ] Với mỗi event: trigger khác nhau? → cần TC riêng
|
|
50
|
+
- [ ] Có field nhạy cảm (SĐT, PII) KHÔNG ĐƯỢC vào event? → cần TC verify âm riêng
|
|
51
|
+
|
|
52
|
+
**d. Privacy/security assertions âm:**
|
|
53
|
+
- [ ] Spec có nói "KHÔNG ghi", "KHÔNG hiển thị", "chỉ đọc", "KHÔNG vào event"? → ghi ra, cần TC riêng
|
|
54
|
+
- [ ] "Read-only + che X/hiện Y" → 2 TC riêng: (1) hiển thị đúng che/hiện, (2) không chỉnh sửa được
|
|
55
|
+
|
|
56
|
+
**e. Validation kế thừa từ UC/AC khác:**
|
|
57
|
+
- [ ] Spec có reference "chuẩn hoá theo ACx", "logic tương tự UCy", "validation như màn Z"? → đọc UC/AC đó
|
|
58
|
+
- [ ] Liệt kê TẤT CẢ scenario normalization của UC nguồn chưa có trong UC hiện tại
|
|
59
|
+
|
|
60
|
+
**f. AC có sub-cases:**
|
|
61
|
+
- [ ] Mỗi AC dạng "(1)...→...; (2)...→...; (3)...→..." → đếm số sub-cases, mỗi sub-case 1 TC
|
|
28
62
|
|
|
29
63
|
---
|
|
30
64
|
|
|
@@ -49,11 +83,11 @@ Với rule có nhiều điều kiện kết hợp → gợi ý dựng **Decision
|
|
|
49
83
|
|
|
50
84
|
## Output
|
|
51
85
|
|
|
52
|
-
Ghi vào **mục Business Rules** của `{
|
|
53
|
-
(KHÔNG tạo file riêng — qc-analyze chỉ trả 2 file: `REQUIREMENT_ANALYSIS.md` + `
|
|
86
|
+
Ghi vào **mục Business Rules** của `{qc_artifact_dir}REQUIREMENT_ANALYSIS.md`
|
|
87
|
+
(KHÔNG tạo file riêng — qc-analyze chỉ trả 2 file: `REQUIREMENT_ANALYSIS.md` + `DOC_GAP.md`):
|
|
54
88
|
|
|
55
89
|
- Bảng business rule có ID (BR-xx) để TC trace ngược về.
|
|
56
90
|
- Gợi ý các rule cần Decision Table / BVA khi sang qa-designer.
|
|
57
91
|
|
|
58
|
-
Rule MÂU THUẪN / KHÔNG RÕ → ghi vào `{
|
|
92
|
+
Rule MÂU THUẪN / KHÔNG RÕ → ghi vào `{qc_artifact_dir}DOC_GAP.md`
|
|
59
93
|
(loại CONTRADICTORY / AMBIGUOUS, cột "Ảnh hưởng" trỏ BR-xx).
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
---
|
|
2
2
|
version: 1.0
|
|
3
3
|
updated: 2026-06-11
|
|
4
|
-
ported_from:
|
|
4
|
+
ported_from: ui-automation-testing
|
|
5
|
+
upstream_path: skills/qa-tc-analyst/data-flow.md
|
|
6
|
+
upstream_sha: fc0fc3d0f8010e3fb266c16b132eff1b23641a8f
|
|
5
7
|
---
|
|
6
8
|
|
|
7
9
|
# Data Flow — Phân tích luồng dữ liệu
|
|
@@ -52,8 +54,8 @@ Thể hiện luồng dạng bước tuần tự hoặc sơ đồ text:
|
|
|
52
54
|
|
|
53
55
|
## Output
|
|
54
56
|
|
|
55
|
-
Ghi vào **mục Data Flow** của `{
|
|
56
|
-
(KHÔNG tạo file riêng — qc-analyze chỉ trả 2 file: `REQUIREMENT_ANALYSIS.md` + `
|
|
57
|
+
Ghi vào **mục Data Flow** của `{qc_artifact_dir}REQUIREMENT_ANALYSIS.md`
|
|
58
|
+
(KHÔNG tạo file riêng — qc-analyze chỉ trả 2 file: `REQUIREMENT_ANALYSIS.md` + `DOC_GAP.md`):
|
|
57
59
|
|
|
58
60
|
- Sơ đồ/list luồng dữ liệu cho mỗi kịch bản chính.
|
|
59
61
|
- Danh sách integration point + state change + failure point.
|
|
@@ -61,4 +63,4 @@ Ghi vào **mục Data Flow** của `{paths.qc_dir}/{UC-ID}/REQUIREMENT_ANALYSIS.
|
|
|
61
63
|
- Dữ liệu/trạng thái cần chuẩn bị & cleanup → đầu vào fixture cho qa-runner.
|
|
62
64
|
|
|
63
65
|
Chặng nào luồng/hành vi chưa rõ (vd lỗi xử lý ra sao, retry, partial commit) →
|
|
64
|
-
ghi vào `{
|
|
66
|
+
ghi vào `{qc_artifact_dir}DOC_GAP.md` (loại MISSING / OPEN QUESTION).
|