@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
|
@@ -9,6 +9,9 @@ ported_from: ai-automation-qc-base
|
|
|
9
9
|
> Stage 1 của QC automation pipeline native (qc-analyze → qc-plan → qc-design-test → qc-review → qc-run-test → qc-report). Port từ qa-analyst của team QC. Markdown-first: không có script ở đây.
|
|
10
10
|
|
|
11
11
|
## Gate
|
|
12
|
+
|
|
13
|
+
*Checkpoint: **chặn thường** — lệnh ghi 2 file artifact. `--yes` bỏ qua được (gate Bước 3a).*
|
|
14
|
+
|
|
12
15
|
# Gate — Quy trình vào chuẩn cho mọi lệnh
|
|
13
16
|
|
|
14
17
|
Mọi lệnh PHẢI chạy gate này trước khi thực thi phần logic riêng của nó.
|
|
@@ -162,7 +165,7 @@ Mỗi dòng ⚠️/🔴 phải ứng với một trạng thái **context-loader
|
|
|
162
165
|
🔴/⚠️ (không chặn ≠ không báo — người đọc log sau này vẫn cần thấy).
|
|
163
166
|
|
|
164
167
|
|
|
165
|
-
*Lưu ý: Với lệnh này, target ở Bước 1 là một
|
|
168
|
+
*Lưu ý: Với lệnh này, target ở Bước 1 là một **TICKET-ID** (mã PRD), hoặc một UC-ID / file feature / file PRD — cả ba đều quy về TICKET-ID ở §Phạm vi QC. Trạm này chạy cho **cả PRD × một nền**. Đọc spec chính thức của **mọi UC trong phạm vi** — file `.feature` (mang `@trace.id={UC-ID}` và mỗi scenario `@trace.scenario={UC-ID}-SC{N}`), PRD, và design-spec — từ feature package `{paths.specs_dir}/{domain}/{prd-slug}/` (file `.feature` dưới `bdd/`, file PRD `{TICKET-ID}-{prd-slug}.md` ở gốc folder, và design-spec dưới `design-spec/`). Spec của framework CHÍNH LÀ source of truth; đừng suy lại các requirement đã có ở đó. **Ngoài ra đọc tech-doc gộp** `{paths.tech_docs_dir}/{domain}/{prd-slug}/tech-docs/{TICKET-ID}-tech-design.md` làm **nguồn thứ hai** — xem §Đối chiếu tài liệu kỹ thuật.*
|
|
166
169
|
|
|
167
170
|
## Context
|
|
168
171
|
**BẮT BUỘC — đọc `.agent/steps/context-loader.md` và thực thi TOÀN BỘ quy trình trong đó**,
|
|
@@ -174,30 +177,198 @@ placeholder bên dưới sẽ rỗng và lệnh sẽ đọc/ghi sai chỗ.
|
|
|
174
177
|
|
|
175
178
|
---
|
|
176
179
|
|
|
177
|
-
##
|
|
180
|
+
## Phạm vi QC — PRD nào, nền nào, những UC nào
|
|
181
|
+
|
|
182
|
+
# QC Scope — phân giải phạm vi cho mọi lệnh `qc-*`
|
|
183
|
+
|
|
184
|
+
**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à
|
|
185
|
+
cả 6 trạm QC đều cần, để chúng không tự suy mỗi trạm một kiểu:
|
|
186
|
+
|
|
187
|
+
| Biến | Là gì |
|
|
188
|
+
|---|---|
|
|
189
|
+
| `TICKET-ID` | mã PRD — **thư mục artifact QC mang tên này** |
|
|
190
|
+
| `active_platform` | `web` \| `app` \| `system` \| … — một QC pass khoá đúng MỘT nền |
|
|
191
|
+
| `qc_artifact_dir` | `{paths.qc_dir}/{TICKET-ID}/{active_platform}/` |
|
|
192
|
+
| `uc_list` | các UC của (PRD × nền) này, kèm trạng thái BDD từng UC |
|
|
193
|
+
|
|
194
|
+
> **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ữ đã
|
|
195
|
+
> 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
|
|
196
|
+
> artifact vào sai thư mục **trong im lặng**.
|
|
197
|
+
|
|
198
|
+
---
|
|
199
|
+
|
|
200
|
+
## 1 — `TICKET-ID`
|
|
201
|
+
|
|
202
|
+
Artifact QC gom theo **PRD**, không theo UC. Nên mọi trạm phải quy được về `TICKET-ID`:
|
|
203
|
+
|
|
204
|
+
| `$ARGUMENTS` là | Cách lấy |
|
|
205
|
+
|---|---|
|
|
206
|
+
| **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 |
|
|
207
|
+
| **TICKET-ID** | dùng trực tiếp |
|
|
208
|
+
| 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 |
|
|
178
209
|
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
- `draft` (hoặc khác `approved`) → **CHECKPOINT cảnh báo mềm** (không chặn cứng — cho phép QC sớm/prototype):
|
|
182
|
-
```
|
|
183
|
-
⚠️ BDD của {UC-ID} đang ở @trace.status: {status} (chưa duyệt). QC chạy trên BDD chưa chốt có thể phải làm lại.
|
|
184
|
-
Khuyến nghị: review-context (BDD) sạch + người duyệt đặt `# @trace.status: approved` rồi mới chạy QC.
|
|
185
|
-
Vẫn chạy QC bây giờ? (Y/N)
|
|
186
|
-
```
|
|
187
|
-
Chỉ tiếp khi chọn Y.
|
|
210
|
+
Đố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á
|
|
211
|
+
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.)
|
|
188
212
|
|
|
189
213
|
---
|
|
190
214
|
|
|
191
|
-
##
|
|
215
|
+
## 2 — `active_platform`
|
|
216
|
+
|
|
217
|
+
> **PHẢI phân giải TRƯỚC mọi phép đọc `.feature`.** `{UC-ID}-SC{N}` chỉ độc nhất trong
|
|
218
|
+
> (UC × nền), nên một UC đa nền có **nhiều file `.feature`** — `bdd/web/`, `bdd/app/`,
|
|
219
|
+
> `bdd/system/` — và mỗi file mang `@trace.status` **riêng**: bản web có thể `approved`
|
|
220
|
+
> 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
|
|
221
|
+
> 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
|
|
222
|
+
> một bản đã duyệt.
|
|
223
|
+
|
|
224
|
+
Theo thứ tự, dừng ở cái đầu tiên khớp:
|
|
225
|
+
|
|
226
|
+
1. `$ARGUMENTS` nêu nền (`web`/`app`/`system`/…) → dùng.
|
|
227
|
+
2. Target là một file `.feature` → đọc `# @trace.platform` của nó.
|
|
228
|
+
3. Glob `{paths.specs_dir}/{domain}/{prd-slug}/bdd/*/` — **đúng một** thư mục nền → dùng nó.
|
|
229
|
+
4. Glob `{paths.qc_dir}/{TICKET-ID}/*/` — **đúng một** thư mục nền đã có artifact → dùng nó.
|
|
230
|
+
*(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.)*
|
|
231
|
+
5. Nhiều nền mà không suy được → hỏi *"QC pass này cho nền nào? (web/app/system)"*.
|
|
232
|
+
**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
|
|
233
|
+
thư mục và ghi `qc_status` vào sai sổ trace:
|
|
234
|
+
```
|
|
235
|
+
❌ {TICKET-ID} có {n} nền ({list}) — không suy được nền nào cho QC pass này.
|
|
236
|
+
Chạy headless thì phải nêu tường minh: /{lệnh} {TICKET-ID} web --yes
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
Lưu `active_platform`. Từ đây, **mọi** phép đọc `.feature` chỉ đọc thư mục
|
|
240
|
+
`bdd/{active_platform}/` — không trộn SC chéo nền.
|
|
192
241
|
|
|
193
|
-
|
|
242
|
+
---
|
|
243
|
+
|
|
244
|
+
## 3 — `qc_artifact_dir`
|
|
245
|
+
|
|
246
|
+
```
|
|
247
|
+
qc_artifact_dir = {paths.qc_dir}/{TICKET-ID}/{active_platform}/
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
Chứa: `REQUIREMENT_ANALYSIS.md` · `DOC_GAP.md` · `TEST_PLAN.md` · `test-cases/*.Test.md`
|
|
251
|
+
— **mỗi loại đúng MỘT file cho cả PRD**, các UC là mục/hàng bên trong.
|
|
194
252
|
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
- Ngược lại → hỏi: *"QC pass này cho platform nào? (web/app/system)"* và chờ chọn.
|
|
253
|
+
`{paths.qc_dir}` là folder top-level **nhìn thấy** trong repo QC (mặc định `docs/`, **không**
|
|
254
|
+
phải `.agent/` ẩn) để đội QC mở và xử lý output dễ dàng. Spec chính thức ở lại spec submodule
|
|
255
|
+
của PO — đừng ghi artifact QC vào đó.
|
|
199
256
|
|
|
200
|
-
|
|
257
|
+
> **Sổ trace KHÔNG theo layout này.** Nó vẫn là `{paths.trace_dir}/{domain}/{prd-slug}/{UC-ID}-{active_platform}.tsv`
|
|
258
|
+
> — 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
|
|
259
|
+
> **cột `UC`** của bảng gap, không qua đường dẫn file.
|
|
260
|
+
|
|
261
|
+
---
|
|
262
|
+
|
|
263
|
+
## 4 — `uc_list`
|
|
264
|
+
|
|
265
|
+
Glob `{paths.specs_dir}/{domain}/{prd-slug}/bdd/{active_platform}/*.feature`. Mỗi file → một
|
|
266
|
+
UC: đọc `# @trace.id` (mã UC) và `# @trace.status` từ header.
|
|
267
|
+
|
|
268
|
+
Chia hai nhóm:
|
|
269
|
+
|
|
270
|
+
| Nhóm | Điều kiện | Xử lý |
|
|
271
|
+
|---|---|---|
|
|
272
|
+
| **Trong phạm vi** | `@trace.status: approved` | phân tích / thiết kế / chạy bình thường |
|
|
273
|
+
| **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 |
|
|
274
|
+
|
|
275
|
+
In bảng phạm vi ra trước khi làm gì:
|
|
276
|
+
```
|
|
277
|
+
Phạm vi QC — {TICKET-ID} / {active_platform}
|
|
278
|
+
✅ {UC-ID} {tên UC} approved
|
|
279
|
+
⏸ {UC-ID} {tên UC} draft → chưa xét
|
|
280
|
+
→ {n} UC trong phạm vi · {m} chưa xét
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
**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
|
|
284
|
+
trong artifact là dựa trên BDD nháp.
|
|
285
|
+
|
|
286
|
+
**Không UC nào `approved` và không có `--include-draft` → DỪNG:**
|
|
287
|
+
```
|
|
288
|
+
❌ {TICKET-ID} ({active_platform}): 0/{n} UC có BDD approved — không có gì để chạy.
|
|
289
|
+
Cách đúng: người duyệt đặt `# @trace.status: approved` rồi chạy lại.
|
|
290
|
+
Muốn chạy sớm trên BDD nháp (prototype): thêm --include-draft
|
|
291
|
+
```
|
|
292
|
+
|
|
293
|
+
> **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
|
|
294
|
+
> **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à
|
|
295
|
+
> 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
|
|
296
|
+
> thường gặp là cái an toàn, và cái sớm phải nói ra.
|
|
297
|
+
|
|
298
|
+
> **Vì sao `--yes` không thay được `--include-draft`.** `--yes` nghĩa *"tôi không ngồi đây để
|
|
299
|
+
> 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
|
|
300
|
+
> 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.
|
|
301
|
+
|
|
302
|
+
|
|
303
|
+
> **QC chạy trên BDD chưa chốt có thể phải làm lại.** `qc-scope` mặc định chỉ lấy UC có
|
|
304
|
+
> `@trace.status: approved`; UC còn nháp vẫn vào bảng *Phạm vi phân tích* của `DOC_GAP.md`
|
|
305
|
+
> với dấu `⏸ Chưa xét` — **không im lặng bỏ khỏi bảng**, vì "chưa xét" khác "đã xét, sạch".
|
|
306
|
+
> Cố ý QC sớm thì thêm `--include-draft`, và artifact phải ghi rõ nó dựa trên BDD nháp.
|
|
307
|
+
|
|
308
|
+
> **Vì sao trạm này chạy CẢ PRD chứ không từng UC** *(B11)*. Ba lý do, theo thứ tự quan trọng:
|
|
309
|
+
>
|
|
310
|
+
> 1. **Mâu thuẫn chéo UC chỉ lộ ra khi đọc cùng lúc.** UC1 nói một kiểu, UC3 nói kiểu khác —
|
|
311
|
+
> chạy tách từng UC thì về **cấu trúc** là không thể thấy, không phải "khó thấy".
|
|
312
|
+
> 2. **Rẻ hơn.** PRD, bản thiết kế, tài liệu kỹ thuật là nguồn **dùng chung**; chạy per-UC là
|
|
313
|
+
> đọc lại chúng mỗi UC một lượt. Phần dùng chung chiếm đa số đầu vào.
|
|
314
|
+
> 3. **Một tài liệu cho một tính năng** là cách PO và QC vốn làm việc — file gốc của đội QC
|
|
315
|
+
> (`DOC_GAP_FEAT-02-3.md`) không có hậu tố UC, và `qa-planner/test-plan.md` vốn viết
|
|
316
|
+
> *"Test Plan cho một feature"*.
|
|
317
|
+
|
|
318
|
+
---
|
|
319
|
+
|
|
320
|
+
## Đối chiếu tài liệu kỹ thuật *(nguồn thứ hai — bắt lệch nghiệp vụ ↔ kỹ thuật)*
|
|
321
|
+
|
|
322
|
+
Định vị tech-doc gộp cấp PRD: `{paths.tech_docs_dir}/{domain}/{prd-slug}/tech-docs/{TICKET-ID}-tech-design.md`.
|
|
323
|
+
Nó phủ **nhiều UC** — và trạm này cũng phủ nhiều UC, nên đọc **mọi phần chạm `uc_list`**
|
|
324
|
+
(đối chiếu `@trace.ucs` ở header với `uc_list`). Phần thuộc UC ngoài phạm vi (`⏸ Chưa xét`) thì bỏ qua.
|
|
325
|
+
|
|
326
|
+
> **Đây là chỗ layout cấp PRD trả lãi rõ nhất.** Tech-doc gộp là **một** tài liệu phủ cả PRD.
|
|
327
|
+
> Chạy per-UC thì nó bị đọc lại N lần, mỗi lần lọc bỏ gần hết — và mâu thuẫn giữa hai UC trong
|
|
328
|
+
> **cùng** tài liệu đó không lần nào lộ ra, vì không lần nào thấy cả hai.
|
|
329
|
+
|
|
330
|
+
**Không tìm thấy → cảnh báo mềm, KHÔNG chặn** (dự án có thể chưa dựng tech-doc):
|
|
331
|
+
```
|
|
332
|
+
⚠️ Không có tech-doc cho {TICKET-ID} — phân tích chỉ dựa trên PRD + BDD + design-spec.
|
|
333
|
+
Lệch giữa yêu cầu nghiệp vụ và hợp đồng kỹ thuật (enum, mã lỗi, ràng buộc field) sẽ KHÔNG được phát hiện ở trạm này.
|
|
334
|
+
```
|
|
335
|
+
|
|
336
|
+
**Có → đối chiếu các mục sau với PRD/BDD, mỗi chỗ vênh là một gap `CONTRADICTORY`:**
|
|
337
|
+
|
|
338
|
+
| Mục tech-doc | Đối chiếu gì với PRD/BDD |
|
|
339
|
+
|---|---|
|
|
340
|
+
| §3 Mô hình dữ liệu | thực thể/field/quan hệ PRD nhắc tới có khớp không |
|
|
341
|
+
| **§4 Hợp đồng API** | **enum & tập giá trị hợp lệ** · ràng buộc field (độ dài, định dạng, bắt buộc) · **mã lỗi** — PRD nêu bao nhiêu nhánh lỗi, contract định nghĩa bao nhiêu |
|
|
342
|
+
| §4.5 Ánh xạ component UI | màn/component PRD·design-spec mô tả có mặt đủ không |
|
|
343
|
+
| §5 Luồng chính | thứ tự bước, nhánh rẽ có khớp scenario `.feature` không |
|
|
344
|
+
| §6 Điểm tích hợp | side-effect PRD nêu (gửi sự kiện, gọi dịch vụ khác) có được định nghĩa không |
|
|
345
|
+
| §8 Xử lý lỗi & biên | trường hợp biên PRD nêu có đường xử lý không, và ngược lại |
|
|
346
|
+
|
|
347
|
+
> **Vì sao mục này tồn tại.** Có một lớp gap **chỉ lộ ra khi so hai loại tài liệu với nhau** —
|
|
348
|
+
> đọc riêng bên nào cũng thấy hợp lý. Ca điển hình: PRD viết *"chọn lớp 1–6"*, contract định
|
|
349
|
+
> nghĩa enum `1..9`. Không ai đọc cả hai thì không ai thấy, và nó ra tận lúc chạy thật.
|
|
350
|
+
> **Đây là lý do trạm này đọc tech-doc — không phải để hiểu kỹ thuật, mà để bắt chỗ hai bên nói khác nhau.**
|
|
351
|
+
|
|
352
|
+
### §12 GAP Register — ĐỌC, KHÔNG GHI
|
|
353
|
+
|
|
354
|
+
Tech-doc có sổ ẩn số thiết kế riêng (`§12`), với vòng đời và người chịu trách nhiệm riêng, và
|
|
355
|
+
`/generate-code` đã canh nó. **Trạm này chỉ đọc, tuyệt đối không ghi vào.**
|
|
356
|
+
|
|
357
|
+
Với mỗi mục `open` trong §12 chạm **bất kỳ UC trong `uc_list`**:
|
|
358
|
+
- **KHÔNG mở gap mới** trong `DOC_GAP.md` về cùng chuyện đó.
|
|
359
|
+
- Ghi vào `REQUIREMENT_ANALYSIS.md` mục *"Đang chờ chốt (từ §12 tech-doc)"*: `{id}` · **UC** · điều chưa biết · owner · severity.
|
|
360
|
+
- Test case chạm nó về sau sẽ bị chặn — nhưng bị chặn bởi **một mục đã có người xử lý**, không phải bởi một câu hỏi mới gửi PO.
|
|
361
|
+
|
|
362
|
+
> **Vì sao không ghi vào.** Một ẩn số đã nằm trong §12 nghĩa là **đã có người đang lo**: có
|
|
363
|
+
> owner, có mức chặn, có cổng chặn sinh code. Mở lại nó thành gap QC là gửi PO một câu hỏi
|
|
364
|
+
> về thứ không phải việc của PO, và tạo hai sổ cùng theo dõi một chuyện — rồi chúng lệch nhau.
|
|
365
|
+
> Đây đúng là **câu hỏi lọc Q1** của `steps/gap-verify.md` (*"chỗ này đã được trả lời ở tài liệu
|
|
366
|
+
> khác chưa?"*), chỉ mở rộng phạm vi "tài liệu khác" thêm một nguồn.
|
|
367
|
+
|
|
368
|
+
**Ngoại lệ — mục `spec-defect` là việc của PO.** §12 phân ba loại: `nội tại` (backend tự quyết) ·
|
|
369
|
+
`cross-service` (đội khác) · `spec-defect` (PRD/BDD sai hoặc thiếu). Hai loại đầu → ghi "đang chờ".
|
|
370
|
+
Loại thứ ba **đúng là gap tài liệu** → vẫn ghi vào `DOC_GAP.md` (cột `UC` = UC bị chạm), trỏ
|
|
371
|
+
ngược về `{id}` của §12 để không đếm hai lần.
|
|
201
372
|
|
|
202
373
|
---
|
|
203
374
|
|
|
@@ -225,45 +396,235 @@ Thứ tự điển hình: spec-breakdown → business-rules / data-flow → acce
|
|
|
225
396
|
|
|
226
397
|
File `.feature` chính thức đã định nghĩa scenario là `@trace.scenario={UC-ID}-SC{N}` với
|
|
227
398
|
`@trace.business_rules`. Map mọi `BR-xx` / `AC-xx` bạn tạo ra tới `{UC-ID}-SC{N}` sở hữu nó
|
|
228
|
-
và ghi lại mapping —
|
|
399
|
+
và ghi lại mapping — **làm cho từng UC trong `uc_list`**, và `BR`/`AC` phải mang rõ UC của nó
|
|
400
|
+
(một file phân tích giờ phủ nhiều UC, nên `BR-01` không còn tự phân biệt được là của UC nào) — qc-design-test và qc-run-test cần nó để gắn tag
|
|
229
401
|
`@trace.verifies` cho test và ghi `qc_status` theo từng scenario.
|
|
230
402
|
|
|
231
|
-
##
|
|
403
|
+
## Quét gap — hai nguồn, gộp rồi mới thẩm định
|
|
404
|
+
|
|
405
|
+
Gap đến từ **hai chỗ**, và chúng bổ sung nhau chứ không thay thế:
|
|
406
|
+
|
|
407
|
+
| Nguồn | Trả lời câu | Gap là |
|
|
408
|
+
|---|---|---|
|
|
409
|
+
| **4 kỹ năng phân tích** ở trên | *"yêu cầu là gì?"* | sản phẩm phụ — đang bóc luật nghiệp vụ thì gặp chỗ mâu thuẫn |
|
|
410
|
+
| **Quét theo lăng kính** *(dưới đây)* | *"còn thiếu gì?"* | mục tiêu chính |
|
|
411
|
+
|
|
412
|
+
### Quét theo lăng kính
|
|
413
|
+
|
|
414
|
+
Chạy `steps/review-fanout.md` với:
|
|
415
|
+
|
|
416
|
+
| Tham số | Giá trị |
|
|
417
|
+
|---|---|
|
|
418
|
+
| `DIMENSIONS` | **4 lăng kính** — `D2 Xử lý lỗi` · `D3 Giao diện` · `D4 Dữ liệu & cấu hình` · `D5 Đối chiếu chéo` **(thu hẹp — xem dưới)** *(định nghĩa ở `{paths.qc_skills_dir}/qa-analyst/exhaustive-gap-scanner.md`)* |
|
|
419
|
+
| `FINDINGS SCHEMA` | như §Output dưới đây |
|
|
420
|
+
| `GRANULARITY` | **`auto`** — chia theo ngưỡng kích thước, KHÔNG ép mịn theo từng UC |
|
|
421
|
+
| `VERIFY` | **`off`** — thẩm định chạy MỘT lần ở bước sau, trên tập đã gộp |
|
|
422
|
+
|
|
423
|
+
**`D5` chạy ở dạng THU HẸP — chỉ 2 trong 4 cặp tài liệu:**
|
|
424
|
+
|
|
425
|
+
| Cặp | |
|
|
426
|
+
|---|---|
|
|
427
|
+
| `PRD ↔ design-spec/` | ✅ **SO** — không ai đối chiếu nội dung. `/generate-bdd` chỉ kiểm `Built from PRD` (số phiên bản); cùng phiên bản mà nội dung lệch thì lọt |
|
|
428
|
+
| `bdd/{platform}/ ↔ design-spec/` | ✅ **SO** — không ai |
|
|
429
|
+
| `PRD ↔ bdd/` | ❌ bỏ — `/review-context` **B1** đã làm |
|
|
430
|
+
| `PRD·bdd/ ↔ tech-docs/` | ❌ bỏ — §Đối chiếu tài liệu kỹ thuật **ở trên** đã làm |
|
|
431
|
+
|
|
432
|
+
> **Cả hai cặp SO đều dính `design-spec/`** — artifact duy nhất trong feature package mà **không
|
|
433
|
+
> tài liệu nào đối chiếu nội dung với nó**. Đừng lẫn với `tech-docs/`: `design-spec/` là *giao diện
|
|
434
|
+
> Designer vẽ*, `tech-docs/` là *hợp đồng hệ thống* — và `tech-docs/` đã được phủ ở §trên.
|
|
435
|
+
>
|
|
436
|
+
> Trạm này **đã đọc `design-spec/`** từ trước (nó nằm trong danh sách nguồn ở Gate), nên `D5`
|
|
437
|
+
> không nạp thêm file nào — chỉ bắt nó **so** thay vì chỉ **đọc**. Rẻ hơn một lăng kính thường.
|
|
438
|
+
|
|
439
|
+
**`D1 Luật nghiệp vụ` là lăng kính duy nhất KHÔNG bật:** `qa-analyst/business-rules.md` đã hỏi
|
|
440
|
+
4/5 câu của nó, và hỏi cụ thể hơn — *"min/max · ký tự cho phép · trim · định dạng"* thay vì
|
|
441
|
+
*"ngưỡng đã chốt chưa"*.
|
|
442
|
+
|
|
443
|
+
> **Ghi lại vì sao `D5` từng bị tắt:** lý do ban đầu là *"trùng nhiều"* — **đúng một nửa**. Nó phủ
|
|
444
|
+
> **bốn** cặp, chỉ **hai** cặp đã có người làm. Sai vì suy từ ấn tượng thay vì đếm danh sách; bảng
|
|
445
|
+
> kiểm chứng 31 câu hỏi (`docs/plans/qc-implementation-log.md`) là thứ đáng lẽ phải làm **trước**
|
|
446
|
+
> khi quyết. Đừng tắt lại `D5` mà không đọc bảng đó.
|
|
447
|
+
|
|
448
|
+
> **`GRANULARITY = auto`, không phải `per-uc`.** `/refine-prd` ép mịn theo từng UC vì ở tầng PRD
|
|
449
|
+
> một gap bỏ sót **im lặng đi tiếp** tới tận lúc chạy thật. Ở đây khác: gap bỏ sót còn **bốn lớp
|
|
450
|
+
> chặn phía sau** — trạm 3 bật ngược khi không viết nổi giá trị mong đợi, trạm 4 soát độ phủ,
|
|
451
|
+
> trạm 5 phân loại lỗi thật vs script sai. Ép mịn ở đây tốn gấp ~3 lần cho tính năng nhỏ mà đổi
|
|
452
|
+
> lấy một lưới an toàn đã có sẵn ba lớp khác.
|
|
232
453
|
|
|
233
|
-
|
|
234
|
-
|
|
454
|
+
### Gộp trước, thẩm định sau
|
|
455
|
+
|
|
456
|
+
Gộp gap từ **cả hai nguồn** vào một tập trước khi sang bước thẩm định.
|
|
457
|
+
|
|
458
|
+
> **Không thẩm định từng nguồn riêng.** Phép kiểm `T6` của `gap-verify` là *"hai gap cùng gốc
|
|
459
|
+
> thì gộp lại"* — nó chỉ chạy được khi **thấy toàn bộ** tập. Thẩm định hai lần trên hai tập rời
|
|
460
|
+
> thì không bắt được trùng lặp chéo nguồn, và PO nhận hai câu hỏi giống nhau.
|
|
461
|
+
|
|
462
|
+
---
|
|
463
|
+
|
|
464
|
+
## DOC_GAP (bắt buộc)
|
|
465
|
+
|
|
466
|
+
Luôn tạo **đúng MỘT** file gap cho cả (PRD × nền) theo
|
|
467
|
+
`{paths.qc_skills_dir}/qa-analyst/DOC_GAP.template.md` — các UC là các hàng bên trong, phân
|
|
468
|
+
biệt bằng cột `UC`:
|
|
469
|
+
- **Bảng 11 cột**, cột 2 là `UC`. ID gap `GAP-UC{N}-{nnn}` (vd `GAP-UC1-001`); gap thuộc cả
|
|
470
|
+
PRD → `GAP-GEN-{nnn}`. Đánh số **độc lập trong từng UC** — phân tích lại UC1 KHÔNG được làm
|
|
471
|
+
đổi số gap của UC2, vì test case đã có đang trỏ `🚫 Block: [GAP-UC2-003]`.
|
|
472
|
+
- **Section `Phạm vi phân tích`** — mỗi UC một hàng kèm `@trace.status`, đã phân tích chưa, số
|
|
473
|
+
gap. UC ngoài phạm vi ghi `⏸ Chưa xét`, **không bỏ khỏi bảng**.
|
|
474
|
+
- Mỗi gap phân loại MISSING / AMBIGUOUS / CONTRADICTORY / ASSUMPTION / OPEN QUESTION, với severity (🔴 Blocker → ⚪ Low) và function/BR/AC bị ảnh hưởng.
|
|
235
475
|
- Không bao giờ bịa câu trả lời; đánh dấu giả định là `ASSUMPTION` để PO/dev confirm.
|
|
236
|
-
- Bất kỳ `🔴 Blocker` nào còn `Open` ⇒ UC
|
|
476
|
+
- Bất kỳ `🔴 Blocker` nào còn `Open` ⇒ **UC ở cột `UC` của hàng đó** chưa sẵn sàng cho
|
|
477
|
+
qc-design-test — bàn giao cho qc-plan. *Chặn theo từng UC, KHÔNG chặn cả PRD:* một blocker ở
|
|
478
|
+
UC3 không có lý do gì dừng việc thiết kế test cho UC1. Ghi rõ UC nào bị chặn ở report.
|
|
237
479
|
- **Đẩy các defect spec thực sự lên PO (không chỉ giữ local).** Một blocker là lỗi thật
|
|
238
480
|
trong spec chính thức — `AMBIGUOUS` / `CONTRADICTORY` / `MISSING` trong PRD/BDD — phải tới
|
|
239
|
-
PO qua feedback flow, không chỉ nằm trong `
|
|
481
|
+
PO qua feedback flow, không chỉ nằm trong `DOC_GAP.md`: tạo `/report-bug {UC-ID} {desc}`
|
|
482
|
+
(`{UC-ID}` lấy từ cột `UC` của hàng gap — bug đi theo UC, không theo PRD)
|
|
240
483
|
(BUG_FLOW của nó phân loại PRD vs BDD), hoặc `/propose-scenario {UC-ID}` nếu gap là thiếu test
|
|
241
484
|
coverage. Gap `ASSUMPTION` / `OPEN QUESTION` được confirm qua questions-for-dev của qc-plan — không file thành bug.
|
|
242
485
|
|
|
243
|
-
|
|
486
|
+
### Thẩm định trước khi bàn giao *(bắt buộc)*
|
|
244
487
|
|
|
245
|
-
|
|
246
|
-
|
|
488
|
+
Sinh xong `DOC_GAP.md`, **đọc `.agent/steps/gap-verify.md` và chạy toàn bộ quy trình trong đó**
|
|
489
|
+
với:
|
|
490
|
+
- `FINDINGS` = mọi gap đang `Open` trong `DOC_GAP.md`
|
|
491
|
+
- `EVIDENCE_ROOT` = `{paths.specs_dir}` — spec repo của PO, **không** phải `{paths.qc_dir}`
|
|
492
|
+
- `VERDICT_FIELD` = cột `Trạng thái` + `Câu trả lời` của bảng gap
|
|
493
|
+
- `RERATE` = `on`
|
|
247
494
|
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
495
|
+
Gap rớt thẩm định được **đóng kèm lý do**, KHÔNG xoá — người đọc phải kiểm chứng được vì sao
|
|
496
|
+
nó bị loại. Cập nhật `Tổng số gap` + bảng ưu tiên sau khi áp verdict, và in khối
|
|
497
|
+
`[GAP VERIFY]` + cam kết cuối vào report.
|
|
498
|
+
|
|
499
|
+
> **Vì sao bắt buộc, không phải tuỳ chọn.** Bước phân tích ở trên chỉ có lực **tìm thêm** —
|
|
500
|
+
> bốn skill lần lượt quét spec và mỗi cái đều được khuyến khích ghi ra chỗ nghi ngờ. Không có
|
|
501
|
+
> bước nào hỏi ngược *"cái vừa ghi có thật không?"*. Hệ quả đo được ở đội QC: phần lớn gap sinh
|
|
502
|
+
> ra là gap ảo — spec đã trả lời ở tài liệu khác, hoặc trích dẫn sai, hoặc là chuyện QC tự quyết
|
|
503
|
+
> được. Mà gap ảo không chỉ tốn thời gian PO: nó **làm PO mất tin vào cả danh sách**, và lúc đó
|
|
504
|
+
> những gap thật cũng chết theo. `gap-verify` là bộ lọc duy nhất đứng giữa hai chuyện đó.
|
|
505
|
+
|
|
506
|
+
## Output
|
|
507
|
+
|
|
508
|
+
Ghi **hai file** dưới `{qc_artifact_dir}` (= `{paths.qc_dir}/{TICKET-ID}/{active_platform}/`)
|
|
509
|
+
+ **một** dưới `{paths.refinement_dir}/`.
|
|
510
|
+
|
|
511
|
+
**Mỗi loại đúng MỘT file cho cả PRD** — đừng tách một-file-mỗi-UC, và cũng đừng tách
|
|
512
|
+
một-file-mỗi-bước (không có file spec-breakdown / business-rules / data-flow / AC riêng):
|
|
513
|
+
|
|
514
|
+
1. **`{qc_artifact_dir}REQUIREMENT_ANALYSIS.md`** — bản phân tích hợp nhất duy nhất cho cả PRD.
|
|
515
|
+
Mở đầu bằng **bảng `Phạm vi phân tích`** (cùng nội dung với bảng trong `DOC_GAP.md`), rồi
|
|
516
|
+
**một mục cho mỗi UC trong phạm vi**, mỗi mục theo thứ tự: phân rã requirement → bảng
|
|
517
|
+
business-rule (`BR-xx`) → data-flow → acceptance-criteria (`AC-xx`), mỗi `BR`/`AC` map tới
|
|
518
|
+
`{UC-ID}-SC{N}` (của `.feature` nền này) sở hữu nó.
|
|
519
|
+
Thêm một mục **"Mâu thuẫn chéo UC"** — chỗ hai UC của cùng PRD nói khác nhau. Rỗng thì ghi
|
|
520
|
+
"Không có". *Đây là thứ chỉ trạm cấp PRD nhìn thấy được; đừng bỏ mục.*
|
|
521
|
+
Cuối file thêm mục **"Đang chờ chốt (từ §12 tech-doc)"** — các ẩn số thiết kế `open` chạm
|
|
522
|
+
các UC trong phạm vi (`{id}` · UC · điều chưa biết · owner · severity). Rỗng thì ghi
|
|
523
|
+
"Không có"; **đừng bỏ mục**.
|
|
524
|
+
2. **`{qc_artifact_dir}DOC_GAP.md`** — file gap, theo
|
|
525
|
+
`{paths.qc_skills_dir}/qa-analyst/DOC_GAP.template.md` + luật viết ở
|
|
526
|
+
`{paths.qc_skills_dir}/qa-analyst/spec-issue-reporter.md`. Bắt buộc:
|
|
527
|
+
- **Bảng 11 cột** đúng thứ tự, có cột **`UC`** (cột 2) và cột **Giao cho đội** (Dev / PO / BA / Design / Kiến trúc / Dữ liệu).
|
|
528
|
+
- Section **"Phạm vi phân tích"** ngay sau metadata — mỗi UC một hàng kèm `@trace.status`,
|
|
529
|
+
đã phân tích chưa, số gap. UC ngoài phạm vi ghi `⏸ Chưa xét`.
|
|
530
|
+
- Ô câu hỏi đủ **bốn phần** tách bằng `<br/>`: **Bối cảnh → Vấn đề → Tại sao quan trọng → Gợi ý**.
|
|
531
|
+
*Ba phần đầu cho PO xếp ưu tiên; phần cuối cho PO trả lời nhanh mà không phải nghĩ lại từ đầu.*
|
|
532
|
+
- Section **"Tài liệu đầu vào đã đọc để phân tích"** đặt ngay sau metadata — liệt kê **đủ** mọi
|
|
533
|
+
file đã mở. Đây là căn cứ độ phủ: không có nó thì không ai phân biệt được *"đã đọc và không thấy"*
|
|
534
|
+
với *"chưa đọc"*.
|
|
535
|
+
- Mức nặng nhất dùng từ **`🔴 Blocker`** (không phải `Critical`) — `/qc-run-test` đọc đúng từ này
|
|
536
|
+
để đặt *"scenario đang chờ PO"* vào sổ trace.
|
|
537
|
+
3. **`{paths.refinement_dir}/{TICKET-ID}-qa-findings.yaml`** — **cùng dữ liệu gap**, ở định dạng Review Board đọc được. Xem §Bản findings dưới đây.
|
|
252
538
|
|
|
253
539
|
`{paths.qc_dir}` là folder top-level NHÌN THẤY trong QC repo (mặc định `docs/`, **không** phải
|
|
254
540
|
`.agent/review/` ẩn) để team QC mở và xử lý output dễ dàng. Spec chính thức ở lại
|
|
255
541
|
spec submodule của PO — đừng ghi phân tích vào đó.
|
|
256
542
|
|
|
543
|
+
### Bản findings — một nguồn, hai mặt
|
|
544
|
+
|
|
545
|
+
File `.yaml` và `DOC_GAP.md` là **cùng một tập gap**, không phải hai tập. Sinh `DOC_GAP.md`
|
|
546
|
+
trước (nó là bản người đọc), rồi **render** sang `.yaml` — đừng phân tích lại lần hai.
|
|
547
|
+
|
|
548
|
+
Dùng **đúng schema của `/refine-prd`** để Review Board đọc được cả hai loại file:
|
|
549
|
+
|
|
550
|
+
```yaml
|
|
551
|
+
prd_source: "{paths.specs_dir}/{domain}/{prd-slug}/{TICKET-ID}-{prd-slug}.md"
|
|
552
|
+
ticket_id: "{TICKET-ID}"
|
|
553
|
+
platform: "{active_platform}"
|
|
554
|
+
ucs: ["{UC-ID}", "…"] # các UC TRONG phạm vi (approved) — theo thứ tự
|
|
555
|
+
ucs_skipped: ["{UC-ID}"] # UC chưa xét, kèm lý do ở DOC_GAP §Phạm vi phân tích
|
|
556
|
+
generated_at: "{ISO datetime}"
|
|
557
|
+
generated_by: "qc-analyze"
|
|
558
|
+
status: "pending_review"
|
|
559
|
+
|
|
560
|
+
findings:
|
|
561
|
+
- id: "F001"
|
|
562
|
+
lens: "QA" # LUÔN là QA — file này chỉ có một lăng kính
|
|
563
|
+
severity: "critical" # critical | major | minor ← map từ 🔴/🟠/🟡⚪ của DOC_GAP
|
|
564
|
+
section: "{section PRD/BDD chứa vấn đề}"
|
|
565
|
+
uc_id: "{UC-ID}"
|
|
566
|
+
quote: "{trích nguyên văn ≤120 ký tự từ spec tại đúng chỗ}"
|
|
567
|
+
finding: "{gap là gì}"
|
|
568
|
+
suggestion: "{cần PO/BA làm rõ điều gì}"
|
|
569
|
+
resolution_edge_cases: [] # để [] — phân tích bậc-hai là việc của /refine-prd
|
|
570
|
+
auto_fixable: false # LUÔN false — xem cảnh báo dưới
|
|
571
|
+
status: "pending"
|
|
572
|
+
applied_via: ""
|
|
573
|
+
gap_ref: "GAP-UC1-001" # trỏ ngược về hàng trong DOC_GAP.md (ID mang UC)
|
|
574
|
+
|
|
575
|
+
summary:
|
|
576
|
+
total_findings: {N}
|
|
577
|
+
by_severity: { critical: {N}, major: {N}, minor: {N} }
|
|
578
|
+
by_lens: { QA: {N} }
|
|
579
|
+
recommendation: "APPROVED_WITH_MINOR_CHANGES | NEEDS_REVISION | BLOCKED"
|
|
580
|
+
```
|
|
581
|
+
|
|
582
|
+
> **`auto_fixable` LUÔN `false`, và KHÔNG có `--resume` cho file này.**
|
|
583
|
+
>
|
|
584
|
+
> Review Board có nút *"chấp nhận rồi tự sửa PRD"*. Với gap của `/refine-prd` thì đúng — nó chạy
|
|
585
|
+
> ở **thời điểm PRD**, sửa PRD lúc đó là sửa đúng chỗ đúng lúc.
|
|
586
|
+
>
|
|
587
|
+
> Gap của lệnh này phát hiện **sau khi code đã xong**. Tự sửa PRD ở thời điểm đó là **sửa sau lưng
|
|
588
|
+
> cả dây chuyền**: BDD sinh từ PRD cũ, code sinh từ BDD đó, sổ kết quả kiểm thử neo vào scenario
|
|
589
|
+
> của BDD đó. Đổi PRD mà không đi lại đường ấy thì mọi thứ phía sau nói dối.
|
|
590
|
+
>
|
|
591
|
+
> Đường đúng vẫn là kênh đã có: `/report-bug` cho defect spec thật, `/propose-scenario` cho thiếu
|
|
592
|
+
> độ phủ. File `.yaml` này để **PO đọc và quyết trong một chỗ quen**, không phải để máy tự áp.
|
|
593
|
+
|
|
594
|
+
**File riêng, không ghi chung với `/refine-prd`.** Cả hai giờ đều ở cấp PRD, nên khác biệt nằm
|
|
595
|
+
ở **hậu tố**: `{TICKET-ID}-qa-findings.yaml` (trạm này) vs `{prd-slug}-findings.yaml`
|
|
596
|
+
(`/refine-prd`). Đừng gộp. Ghi chung sẽ phá trường `applied_to_version` mà `/refine-prd` dùng để
|
|
597
|
+
phân biệt *"PRD đổi do chính tôi áp fix"* với *"có người lạ sửa"* — và nó sẽ mãi mãi tưởng có
|
|
598
|
+
người sửa sau lưng, mỗi lần chạy đều quét lại toàn bộ kèm cảnh báo giả.
|
|
599
|
+
|
|
600
|
+
---
|
|
601
|
+
|
|
257
602
|
## Report
|
|
258
603
|
|
|
259
604
|
**Đọc `.agent/steps/report-footer.md`** và áp đúng khuôn footer trong đó (Status Badge ·
|
|
260
605
|
Output Artifacts · Next) cho report cuối, kèm khối bên dưới.
|
|
261
606
|
|
|
262
607
|
```
|
|
263
|
-
/qc-analyze Hoàn tất — {
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
608
|
+
/qc-analyze Hoàn tất — {TICKET-ID} ({active_platform})
|
|
609
|
+
Phạm vi: {n}/{N} UC phân tích{nếu có UC chưa xét: " · ⏸ {m} chưa xét: {danh sách UC-ID} (BDD chưa approved)"}
|
|
610
|
+
Files : {paths.qc_dir}/{TICKET-ID}/{active_platform}/REQUIREMENT_ANALYSIS.md + DOC_GAP.md (11 cột)
|
|
611
|
+
{paths.refinement_dir}/{TICKET-ID}-qa-findings.yaml ← mở bằng Review Board (chuột phải)
|
|
612
|
+
Nguồn : PRD · BDD({active_platform}, {n} UC) · design-spec · tech-doc{nếu thiếu tech-doc: " (THIẾU — không đối chiếu được nghiệp vụ ↔ kỹ thuật)"}
|
|
613
|
+
Quét : 4 kỹ năng phân tích + 4 lăng kính (xử lý lỗi · giao diện · dữ liệu & cấu hình
|
|
614
|
+
· đối chiếu chéo: PRD↔design-spec, bdd↔design-spec)
|
|
615
|
+
Verify: {raw} gap thô → {N} còn Open (❌ {invalid} bịa/đã-trả-lời · ⚠️ {reclass} không phải gap nghiệp vụ · 🔁 {merge} trùng)
|
|
616
|
+
Gaps : {N} ({blockers} blocker) — theo UC: {UC1: n · UC2: n · …}{nếu có: " · toàn PRD: {n}"}
|
|
617
|
+
← blocker là spec-defect? → /report-bug {UC-ID của hàng đó} | coverage gap → /propose-scenario {UC-ID}
|
|
618
|
+
Chéo UC: {X} mâu thuẫn giữa các UC của cùng PRD (đã ghi vào REQUIREMENT_ANALYSIS §Mâu thuẫn chéo UC)
|
|
619
|
+
Chặn : {danh sách UC có 🔴 Blocker còn Open} — các UC còn lại vẫn thiết kế test được bình thường
|
|
620
|
+
Chờ chốt: {G} ẩn số §12 tech-doc đang open chạm các UC này (đã ghi vào REQUIREMENT_ANALYSIS, KHÔNG hỏi lại PO)
|
|
621
|
+
SC map: {M} BR/AC map tới {K} scenario
|
|
622
|
+
Next : /qc-plan {TICKET-ID} {active_platform} ← rủi ro / what-if / câu hỏi cho dev
|
|
623
|
+
(giải quyết các gap 🔴 Blocker với PO/Dev trước)
|
|
269
624
|
```
|
|
625
|
+
|
|
626
|
+
> **Dòng `Next` là bắt buộc in, không phải trang trí.** Dây gốc của đội QC ra **cả** file gap
|
|
627
|
+
> **và** kế hoạch test trong một lần chạy (13/14 lần đo được ở repo của họ). Ở framework đó là
|
|
628
|
+
> **hai lệnh**. Người quen dây cũ sẽ dừng lại ở đây và tưởng đã xong — dòng này là chỗ duy nhất
|
|
629
|
+
> nói cho họ biết còn một bước nữa.
|
|
630
|
+
|