@educa-corp/sdd-framework 0.9.5 → 0.9.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/build.js +11 -1
- package/bin/lint-trace.js +397 -28
- package/bin/self-check.js +183 -12
- package/bin/trace-schema.json +2656 -1981
- package/core/FRAMEWORK_VERSION +1 -1
- package/core/commands/dev-gen-test.md +62 -0
- package/core/commands/generate-code.md +1 -1
- package/core/commands/generate-tech-docs.md +3 -3
- package/core/commands/map-testids.md +88 -11
- package/core/commands/qc-analyze.md +509 -425
- package/core/commands/qc-design-test.md +475 -247
- package/core/commands/qc-plan.md +134 -93
- package/core/commands/qc-review.md +216 -131
- package/core/commands/qc-run-test.md +346 -231
- package/core/commands/validate-traces.md +17 -2
- package/core/rules/workflow.md +40 -0
- package/core/skills/qc/qa-analyst/DOC_GAP.template.md +9 -1
- package/core/skills/qc/qa-designer/shared/duplicate-check-procedure.md +33 -5
- package/core/skills/qc/qa-designer/shared/tc-metadata-format.md +24 -0
- package/core/skills/qc/qa-planner/test-plan.md +7 -0
- 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/steps/qc-scope.md +67 -11
- package/core/steps/qc-stamp.md +142 -0
- package/core/steps/report-footer.md +13 -5
- package/core/templates/tech-design.template.md +3 -3
- package/docs/01-getting-started/quickstart.md +4 -3
- package/docs/02-concepts/architecture.md +14 -0
- package/docs/02-concepts/glossary.md +8 -0
- package/docs/02-concepts/overview.md +3 -2
- package/docs/02-concepts/pipeline-steps/04-bdd.md +1 -1
- package/docs/02-concepts/pipeline-steps/05-tech-docs.md +21 -5
- package/docs/02-concepts/pipeline-steps/06-code.md +12 -2
- package/docs/02-concepts/pipeline-steps/08-qc-automation.md +60 -12
- package/docs/02-concepts/pipeline-steps/README.md +4 -3
- package/docs/02-concepts/traceability.md +2 -2
- package/docs/03-guides/architect.md +2 -2
- package/docs/03-guides/developer.md +5 -2
- package/docs/03-guides/tester-qa.md +17 -5
- package/docs/04-reference/commands.md +6 -3
- package/docs/04-reference/trace-schema.md +1 -1
- package/docs/explain/07-generate-tech-docs.md +5 -3
- package/docs/explain/08-review-tech-docs.md +15 -3
- package/docs/explain/09-generate-code.md +30 -4
- package/docs/explain/10-review-code.md +1 -1
- package/docs/explain/11-map-testids.md +72 -70
- package/docs/explain/12-dev-gen-test.md +1 -1
- package/docs/explain/15-qc-analyze.md +14 -2
- package/docs/explain/16-qc-plan.md +5 -1
- package/docs/explain/17-qc-design-test.md +26 -3
- package/docs/explain/18-qc-review.md +6 -2
- package/docs/explain/19-qc-run-test.md +29 -6
- package/docs/explain/20-qc-report.md +5 -2
- package/docs/explain/README.md +4 -1
- package/package.json +1 -1
|
@@ -1,17 +1,19 @@
|
|
|
1
|
-
---
|
|
2
|
-
version: 1.0
|
|
3
|
-
updated: 2026-06-11
|
|
4
|
-
ported_from: ai-automation-qc-base
|
|
5
|
-
---
|
|
6
|
-
|
|
7
|
-
# /qc-analyze — QC Requirement Analysis
|
|
8
|
-
|
|
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
|
-
|
|
11
|
-
## Gate
|
|
12
|
-
|
|
13
|
-
*Checkpoint: **chặn
|
|
14
|
-
|
|
1
|
+
---
|
|
2
|
+
version: 1.0
|
|
3
|
+
updated: 2026-06-11
|
|
4
|
+
ported_from: ai-automation-qc-base
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# /qc-analyze — QC Requirement Analysis
|
|
8
|
+
|
|
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
|
+
|
|
11
|
+
## Gate
|
|
12
|
+
|
|
13
|
+
*Checkpoint: **chặn CỨNG** — ghi đè DOC_GAP.md đã có → mất cột Trạng thái/Câu trả lời (PO điền TAY, KHÔNG sinh lại được), ĐÁNH SỐ LẠI GAP-ID, phá 🚫 Block trong mọi .Test.md đã sinh. `--yes` KHÔNG bỏ qua được (gate Bước 3a).*
|
|
14
|
+
|
|
15
|
+
*Mức cứng chỉ áp khi `DOC_GAP.md` **đã tồn tại** — lần chạy đầu không ghi đè gì, đi thẳng. Xem §Chạy lại.*
|
|
16
|
+
|
|
15
17
|
# Gate — Quy trình vào chuẩn cho mọi lệnh
|
|
16
18
|
|
|
17
19
|
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ó.
|
|
@@ -163,425 +165,507 @@ Mỗi dòng ⚠️/🔴 phải ứng với một trạng thái **context-loader
|
|
|
163
165
|
- "N" → dừng, hỏi người dùng muốn thay đổi gì.
|
|
164
166
|
- Có `--yes` và mức *chặn thường* → coi như "Y", **nhưng vẫn IN khối CHECKPOINT** nếu có cờ
|
|
165
167
|
🔴/⚠️ (không chặn ≠ không báo — người đọc log sau này vẫn cần thấy).
|
|
166
|
-
|
|
167
|
-
|
|
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.*
|
|
169
|
-
|
|
170
|
-
## Context
|
|
168
|
+
|
|
169
|
+
|
|
170
|
+
*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.*
|
|
171
|
+
|
|
172
|
+
## Context
|
|
171
173
|
**BẮT BUỘC — đọc `.agent/steps/context-loader.md` và thực thi TOÀN BỘ quy trình trong đó**,
|
|
172
174
|
rồi mới tiếp tục phần bên dưới.
|
|
173
175
|
|
|
174
176
|
Bỏ qua bước này thì `{paths.*}`, `{tech_stack.*}`, `{conventions.*}`, guardrail từ
|
|
175
177
|
`project-lessons`, và routing service (chế độ umbrella) đều **chưa được phân giải** — mọi
|
|
176
|
-
placeholder bên dưới sẽ rỗng và lệnh sẽ đọc/ghi sai chỗ.
|
|
177
|
-
|
|
178
|
-
---
|
|
179
|
-
|
|
180
|
-
## Phạm vi QC — PRD nào, nền nào, những UC nào
|
|
181
|
-
|
|
178
|
+
placeholder bên dưới sẽ rỗng và lệnh sẽ đọc/ghi sai chỗ.
|
|
179
|
+
|
|
180
|
+
---
|
|
181
|
+
|
|
182
|
+
## Phạm vi QC — PRD nào, nền nào, những UC nào
|
|
183
|
+
|
|
182
184
|
**BẮT BUỘC — đọc `.agent/steps/qc-scope.md` và thực thi TOÀN BỘ quy trình trong đó**,
|
|
183
185
|
rồi mới tiếp tục phần bên dưới.
|
|
184
186
|
|
|
185
187
|
Nó chốt bốn thứ mà mọi trạm QC đều cần: `TICKET-ID` · `active_platform` ·
|
|
186
|
-
`qc_artifact_dir` · `uc_list` (kèm trạng thái BDD từng UC, và cờ `--
|
|
188
|
+
`qc_artifact_dir` · `uc_list` (kèm trạng thái BDD từng UC, và cờ `--force`).
|
|
187
189
|
Bỏ qua thì artifact QC ghi vào **sai thư mục** và `qc_status` ghi vào **sai sổ trace** —
|
|
188
|
-
cả hai đều xảy ra trong im lặng, không có bước nào phía sau bắt được.
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
>
|
|
203
|
-
>
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
>
|
|
214
|
-
>
|
|
215
|
-
>
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
>
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
**
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
|
357
|
-
|
|
358
|
-
|
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
|
366
|
-
|
|
367
|
-
| `
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
> **
|
|
382
|
-
>
|
|
383
|
-
>
|
|
384
|
-
|
|
385
|
-
>
|
|
386
|
-
>
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
>
|
|
396
|
-
|
|
397
|
-
>
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
`
|
|
435
|
-
|
|
436
|
-
>
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
- **
|
|
544
|
-
|
|
545
|
-
- **
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
190
|
+
cả hai đều xảy ra trong im lặng, không có bước nào phía sau bắt được.
|
|
191
|
+
|
|
192
|
+
---
|
|
193
|
+
|
|
194
|
+
## Stamp phiên bản nguồn
|
|
195
|
+
|
|
196
|
+
**BẮT BUỘC — đọc `.agent/steps/qc-stamp.md` và thực thi phần áp cho lệnh này**,
|
|
197
|
+
rồi mới tiếp tục phần bên dưới.
|
|
198
|
+
|
|
199
|
+
Nó có **hai vế**: §1 **ghi** khối `Nguồn & phiên bản` vào artifact lệnh này sinh ra ·
|
|
200
|
+
§2 **so** stamp của artifact lệnh này ĐỌC với version hiện tại của spec.
|
|
201
|
+
Bỏ vế ghi thì trạm sau không có gì để so; bỏ vế so thì stamp thành một con số không ai
|
|
202
|
+
đọc — và một bộ TC lỗi thời sẽ chạy xanh rồi ghi `pass` **hợp lệ theo mọi phép kiểm**.
|
|
203
|
+
|
|
204
|
+
> **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ó
|
|
205
|
+
> `@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`
|
|
206
|
+
> 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".
|
|
207
|
+
> Cố ý QC sớm thì thêm `--force`, và artifact phải ghi rõ nó dựa trên BDD nháp.
|
|
208
|
+
|
|
209
|
+
> **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:
|
|
210
|
+
>
|
|
211
|
+
> 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 —
|
|
212
|
+
> 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".
|
|
213
|
+
> 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à
|
|
214
|
+
> đọc lại chúng mỗi UC một lượt. Phần dùng chung chiếm đa số đầu vào.
|
|
215
|
+
> 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
|
|
216
|
+
> (`DOC_GAP_FEAT-02-3.md`) không có hậu tố UC, và `qa-planner/test-plan.md` vốn viết
|
|
217
|
+
> *"Test Plan cho một feature"*.
|
|
218
|
+
|
|
219
|
+
---
|
|
220
|
+
|
|
221
|
+
## Đối chiếu tài liệu kỹ thuật *(nguồn thứ hai — bắt lệch nghiệp vụ ↔ kỹ thuật)*
|
|
222
|
+
|
|
223
|
+
Định vị tech-doc gộp cấp PRD: `{paths.tech_docs_dir}/{domain}/{prd-slug}/tech-docs/{TICKET-ID}-tech-design.md`.
|
|
224
|
+
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`**
|
|
225
|
+
(đố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.
|
|
226
|
+
|
|
227
|
+
> **Đâ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.
|
|
228
|
+
> 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
|
|
229
|
+
> **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.
|
|
230
|
+
|
|
231
|
+
**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):
|
|
232
|
+
```
|
|
233
|
+
⚠️ Không có tech-doc cho {TICKET-ID} — phân tích chỉ dựa trên PRD + BDD + design-spec.
|
|
234
|
+
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.
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
**Có → đối chiếu các mục sau với PRD/BDD, mỗi chỗ vênh là một gap `CONTRADICTORY`:**
|
|
238
|
+
|
|
239
|
+
| Mục tech-doc | Đối chiếu gì với PRD/BDD |
|
|
240
|
+
|---|---|
|
|
241
|
+
| §3 Mô hình dữ liệu | thực thể/field/quan hệ PRD nhắc tới có khớp không |
|
|
242
|
+
| **§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 |
|
|
243
|
+
| §4.5 Ánh xạ component UI | màn/component PRD·design-spec mô tả có mặt đủ không |
|
|
244
|
+
| §5 Luồng chính | thứ tự bước, nhánh rẽ có khớp scenario `.feature` không |
|
|
245
|
+
| §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 |
|
|
246
|
+
| §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 |
|
|
247
|
+
|
|
248
|
+
> **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** —
|
|
249
|
+
> đọ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
|
|
250
|
+
> 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.
|
|
251
|
+
> **Đâ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.**
|
|
252
|
+
|
|
253
|
+
### §12 GAP Register — ĐỌC, KHÔNG GHI
|
|
254
|
+
|
|
255
|
+
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à
|
|
256
|
+
`/generate-code` đã canh nó. **Trạm này chỉ đọc, tuyệt đối không ghi vào.**
|
|
257
|
+
|
|
258
|
+
Với mỗi mục `open` trong §12 chạm **bất kỳ UC trong `uc_list`**:
|
|
259
|
+
- **KHÔNG mở gap mới** trong `DOC_GAP.md` về cùng chuyện đó.
|
|
260
|
+
- 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.
|
|
261
|
+
- 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.
|
|
262
|
+
|
|
263
|
+
> **Vì sao không ghi vào.** Một ẩn số đã nằm trong §12 nghĩa là **đã có người đang lo**: có
|
|
264
|
+
> 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
|
|
265
|
+
> 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.
|
|
266
|
+
> Đâ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
|
|
267
|
+
> khác chưa?"*), chỉ mở rộng phạm vi "tài liệu khác" thêm một nguồn.
|
|
268
|
+
|
|
269
|
+
**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) ·
|
|
270
|
+
`cross-service` (đội khác) · `spec-defect` (PRD/BDD sai hoặc thiếu). Hai loại đầu → ghi "đang chờ".
|
|
271
|
+
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ỏ
|
|
272
|
+
ngược về `{id}` của §12 để không đếm hai lần.
|
|
273
|
+
|
|
274
|
+
---
|
|
275
|
+
|
|
276
|
+
## Role
|
|
277
|
+
|
|
278
|
+
Bạn là **QC Analyst** — stage đầu tiên của QC automation pipeline. Lấy requirement
|
|
279
|
+
chính thức (PRD + BDD `.feature` + design-spec) và phân rã thành một mô tả requirement
|
|
280
|
+
CÓ CẤU TRÚC: function, business rule, data flow, acceptance criteria. Bạn **không**
|
|
281
|
+
viết test case chi tiết hay Python (đó là qc-design-test / qc-run-test).
|
|
282
|
+
|
|
283
|
+
Ranh giới với `/qc-plan`: bạn trả lời *"requirement là gì?"*; qc-plan trả lời *"rủi ro ở đâu,
|
|
284
|
+
hỏi dev gì?"*. Khi có gì mơ hồ/thiếu, ghi nó thành gap và bàn giao cho qc-plan — đừng bao giờ bịa câu trả lời.
|
|
285
|
+
|
|
286
|
+
## Skills (`{paths.qc_skills_dir}/qa-analyst/`)
|
|
287
|
+
|
|
288
|
+
Chỉ nạp file cho bước đang làm (mỗi file tự đủ):
|
|
289
|
+
- `spec-breakdown.md` — phân rã spec/PRD/user story thành cấu trúc.
|
|
290
|
+
- `business-rules.md` — trích business rule, điều kiện, ràng buộc (code `BR-xx`).
|
|
291
|
+
- `data-flow.md` — input/output, data flow, điểm tích hợp/thất bại.
|
|
292
|
+
- `acceptance-criteria.md` — acceptance criteria Given/When/Then (code `AC-xx`).
|
|
293
|
+
|
|
294
|
+
Thứ tự điển hình: spec-breakdown → business-rules / data-flow → acceptance-criteria.
|
|
295
|
+
|
|
296
|
+
## Trace mapping (bắt buộc)
|
|
297
|
+
|
|
298
|
+
File `.feature` chính thức đã định nghĩa scenario là `@trace.scenario={UC-ID}-SC{N}` với
|
|
299
|
+
`@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ó
|
|
300
|
+
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ó
|
|
301
|
+
(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
|
|
302
|
+
`@trace.verifies` cho test và ghi `qc_status` theo từng scenario.
|
|
303
|
+
|
|
304
|
+
## Guard — BR-tag *(phép so khớp cơ học, chạy SAU khi ghi file, TRƯỚC CHECKPOINT)*
|
|
305
|
+
|
|
306
|
+
§Trace mapping ở trên đi **một chiều**: từ `BR` bạn tạo ra → `SC` sở hữu nó. Chiều đó đúng và
|
|
307
|
+
cần. Nhưng chiều **ngược lại** — từ tag `@trace.business_rules` đã có trong `.feature` → `BR`
|
|
308
|
+
trong bản phân tích — mới là chiều bắt được **cái bỏ sót**, và nó chưa được kiểm ở đâu.
|
|
309
|
+
|
|
310
|
+
BDD đã tự nói ra một phần đáp án. Mỗi scenario mang tag do `/generate-bdd` ghi khi sinh từ PRD:
|
|
311
|
+
|
|
312
|
+
```gherkin
|
|
313
|
+
# @trace.scenario: FT-101-UC1-SC3
|
|
314
|
+
# @trace.business_rules: FT-101-UC1-BR02, FT-101-UC1-BR07
|
|
315
|
+
```
|
|
316
|
+
|
|
317
|
+
Nếu bản phân tích chỉ có `BR01`–`BR05` thì `BR07` là **rule mà BDD biết mà QC bỏ sót** — và đó
|
|
318
|
+
là một **phép so khớp chuỗi**, máy làm được.
|
|
319
|
+
|
|
320
|
+
### Bốn bước, thuần đếm và so
|
|
321
|
+
|
|
322
|
+
1. **Thu A** — đọc **mọi** `.feature` của `uc_list` (đúng `active_platform`), gom toàn bộ giá trị
|
|
323
|
+
trong tag `@trace.business_rules`.
|
|
324
|
+
2. **Thu B** — gom mọi `BR-xx` trong `REQUIREMENT_ANALYSIS.md` **vừa ghi**.
|
|
325
|
+
3. **So** — `A ∖ B` = rule BDD nhắc mà phân tích không có.
|
|
326
|
+
4. **Xử lý:**
|
|
327
|
+
- `A ∖ B` rỗng → in `Guard BR-tag: khớp {n}/{n}`
|
|
328
|
+
- `A ∖ B` ≠ rỗng → **quay lại PRD lấy nội dung thật của từng rule đó, BỔ SUNG NGAY vào
|
|
329
|
+
`REQUIREMENT_ANALYSIS.md`**, rồi in:
|
|
330
|
+
`⚠️ Guard BR-tag: bổ sung {k} rule BDD đã nhắc mà phân tích bỏ sót: {danh sách}`
|
|
331
|
+
|
|
332
|
+
**Guard TỰ SỬA, không chỉ tự báo.** In cảnh báo rồi để người đi lấp là thêm một dòng nữa để bỏ
|
|
333
|
+
qua. Bạn phải mở PRD, tìm rule đó, viết nội dung thật vào bản phân tích — **không** thêm một
|
|
334
|
+
dòng trống mang tên `BR-xx` cho đủ số. Cảnh báo là để người **biết đã có chuyện gì xảy ra**,
|
|
335
|
+
không phải để họ đi làm việc đó.
|
|
336
|
+
|
|
337
|
+
**Chiều `B ∖ A` KHÔNG phải lỗi.** QC sinh `BR09` mà không tag nào nhắc → có thể QC phát hiện một
|
|
338
|
+
rule BDD chưa phủ. Đó là **phát hiện tốt**: ghi thành một gap trong `DOC_GAP.md` (BDD thiếu
|
|
339
|
+
scenario cho rule này), **đừng xoá**.
|
|
340
|
+
|
|
341
|
+
**In dòng `Guard BR-tag:` kể cả khi sạch.** Guard im lặng khi sạch là guard không ai biết nó tồn
|
|
342
|
+
tại — và không ai phát hiện được khi nó chết.
|
|
343
|
+
|
|
344
|
+
> **Vì sao cần guard mà không phải self-review.** Self-review là agent **tự đọc lại bài của
|
|
345
|
+
> mình**, nên nó bỏ sót đúng chỗ nó đã bỏ sót lúc viết. Guard đọc **một nguồn khác** (tag trong
|
|
346
|
+
> `.feature`, do một lệnh khác ghi) rồi đối chiếu — không phụ thuộc agent có để ý hay không, và
|
|
347
|
+
> chạy như nhau mỗi lần.
|
|
348
|
+
>
|
|
349
|
+
> **Vì sao bỏ sót ở đây đắt nhất trong cả pipeline.** Không có `BR` → `/qc-plan` không xếp rủi ro
|
|
350
|
+
> cho nó → `/qc-design-test` không viết test case → `/qc-run-test` không có gì chạy → báo cáo
|
|
351
|
+
> cuối nói *"coverage 100%"*. Con số đó tính trên mẫu số *"số scenario đã biết"*, không phải
|
|
352
|
+
> *"số rule cần phủ"* — nên nó sai theo hướng nguy hiểm nhất: trông như đã xong.
|
|
353
|
+
|
|
354
|
+
## Quét gap — hai nguồn, gộp rồi mới thẩm định
|
|
355
|
+
|
|
356
|
+
Gap đến từ **hai chỗ**, và chúng bổ sung nhau chứ không thay thế:
|
|
357
|
+
|
|
358
|
+
| Nguồn | Trả lời câu | Gap là |
|
|
359
|
+
|---|---|---|
|
|
360
|
+
| **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 |
|
|
361
|
+
| **Quét theo lăng kính** *(dưới đây)* | *"còn thiếu gì?"* | mục tiêu chính |
|
|
362
|
+
|
|
363
|
+
### Quét theo lăng kính
|
|
364
|
+
|
|
365
|
+
Chạy `steps/review-fanout.md` với:
|
|
366
|
+
|
|
367
|
+
| Tham số | Giá trị |
|
|
368
|
+
|---|---|
|
|
369
|
+
| `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`)* |
|
|
370
|
+
| `FINDINGS SCHEMA` | như §Output dưới đây |
|
|
371
|
+
| `GRANULARITY` | **`auto`** — chia theo ngưỡng kích thước, KHÔNG ép mịn theo từng UC |
|
|
372
|
+
| `VERIFY` | **`off`** — thẩm định chạy MỘT lần ở bước sau, trên tập đã gộp |
|
|
373
|
+
|
|
374
|
+
**`D5` chạy ở dạng THU HẸP — chỉ 2 trong 4 cặp tài liệu:**
|
|
375
|
+
|
|
376
|
+
| Cặp | |
|
|
377
|
+
|---|---|
|
|
378
|
+
| `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 |
|
|
379
|
+
| `bdd/{platform}/ ↔ design-spec/` | ✅ **SO** — không ai |
|
|
380
|
+
| `PRD ↔ bdd/` | ❌ bỏ — `/review-context` **B1** đã làm |
|
|
381
|
+
| `PRD·bdd/ ↔ tech-docs/` | ❌ bỏ — §Đối chiếu tài liệu kỹ thuật **ở trên** đã làm |
|
|
382
|
+
|
|
383
|
+
> **Cả hai cặp SO đều dính `design-spec/`** — artifact duy nhất trong feature package mà **không
|
|
384
|
+
> 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
|
|
385
|
+
> Designer vẽ*, `tech-docs/` là *hợp đồng hệ thống* — và `tech-docs/` đã được phủ ở §trên.
|
|
386
|
+
>
|
|
387
|
+
> Trạm này **đã đọc `design-spec/`** từ trước (nó nằm trong danh sách nguồn ở Gate), nên `D5`
|
|
388
|
+
> 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.
|
|
389
|
+
|
|
390
|
+
**`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
|
|
391
|
+
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ì
|
|
392
|
+
*"ngưỡng đã chốt chưa"*.
|
|
393
|
+
|
|
394
|
+
> **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ủ
|
|
395
|
+
> **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
|
|
396
|
+
> 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**
|
|
397
|
+
> khi quyết. Đừng tắt lại `D5` mà không đọc bảng đó.
|
|
398
|
+
|
|
399
|
+
> **`GRANULARITY = auto`, không phải `per-uc`.** `/refine-prd` ép mịn theo từng UC vì ở tầng PRD
|
|
400
|
+
> 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
|
|
401
|
+
> 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ủ,
|
|
402
|
+
> 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
|
|
403
|
+
> lấy một lưới an toàn đã có sẵn ba lớp khác.
|
|
404
|
+
|
|
405
|
+
### Gộp trước, thẩm định sau
|
|
406
|
+
|
|
407
|
+
Gộp gap từ **cả hai nguồn** vào một tập trước khi sang bước thẩm định.
|
|
408
|
+
|
|
409
|
+
> **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
|
|
410
|
+
> 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
|
|
411
|
+
> 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.
|
|
412
|
+
|
|
413
|
+
---
|
|
414
|
+
|
|
415
|
+
## DOC_GAP (bắt buộc)
|
|
416
|
+
|
|
417
|
+
Luôn tạo **đúng MỘT** file gap cho cả (PRD × nền) theo
|
|
418
|
+
`{paths.qc_skills_dir}/qa-analyst/DOC_GAP.template.md` — các UC là các hàng bên trong, phân
|
|
419
|
+
biệt bằng cột `UC`:
|
|
420
|
+
- **Bảng 11 cột**, cột 2 là `UC`. ID gap `GAP-UC{N}-{nnn}` (vd `GAP-UC1-001`); gap thuộc cả
|
|
421
|
+
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
|
|
422
|
+
đổi số gap của UC2, vì test case đã có đang trỏ `🚫 Block: [GAP-UC2-003]`.
|
|
423
|
+
- **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ố
|
|
424
|
+
gap. UC ngoài phạm vi ghi `⏸ Chưa xét`, **không bỏ khỏi bảng**.
|
|
425
|
+
- 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.
|
|
426
|
+
- Không bao giờ bịa câu trả lời; đánh dấu giả định là `ASSUMPTION` để PO/dev confirm.
|
|
427
|
+
- Bất kỳ `🔴 Blocker` nào còn `Open` ⇒ **UC ở cột `UC` của hàng đó** chưa sẵn sàng **để nghiệm
|
|
428
|
+
thu** — bàn giao cho qc-plan. *Chặn theo từng UC, KHÔNG chặn cả PRD:* một blocker ở UC3 không
|
|
429
|
+
có lý do gì dừng việc thiết kế test cho UC1. Ghi rõ UC nào bị chặn ở report.
|
|
430
|
+
|
|
431
|
+
> **"Chưa sẵn sàng" ≠ "chưa được thiết kế"** *(G66)*. `/qc-design-test` **vẫn chạy được và nên
|
|
432
|
+
> chạy** trên UC bị chặn — TC chạm gap mang dấu `🚫 Block: [GAP-UC{N}-{nnn}]` trỏ về hàng gap,
|
|
433
|
+
> vẫn được `Guard SC coverage` đếm là đã phủ, và **chưa chạy** tới khi gap `Answered`.
|
|
434
|
+
> Cái bị chặn là **chạy test**, không phải **viết test**.
|
|
435
|
+
>
|
|
436
|
+
> *Mã gap mang UC (`GAP-UC1-003`) và luật "đánh số độc lập trong từng UC" ở trên **chỉ có nghĩa
|
|
437
|
+
> vì** test case đang trỏ vào các mã đó. Hiểu "chưa sẵn sàng" thành "đừng thiết kế" là giết cả
|
|
438
|
+
> cơ chế đó.*
|
|
439
|
+
- **Đẩy các defect spec thực sự lên PO (không chỉ giữ local).** Một blocker là lỗi thật
|
|
440
|
+
trong spec chính thức — `AMBIGUOUS` / `CONTRADICTORY` / `MISSING` trong PRD/BDD — phải tới
|
|
441
|
+
PO qua feedback flow, không chỉ nằm trong `DOC_GAP.md`: tạo `/report-bug {UC-ID} {desc}`
|
|
442
|
+
(`{UC-ID}` lấy từ cột `UC` của hàng gap — bug đi theo UC, không theo PRD)
|
|
443
|
+
(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
|
|
444
|
+
coverage. Gap `ASSUMPTION` / `OPEN QUESTION` được confirm qua questions-for-dev của qc-plan — không file thành bug.
|
|
445
|
+
|
|
446
|
+
### Thẩm định trước khi bàn giao *(bắt buộc)*
|
|
447
|
+
|
|
448
|
+
Sinh xong `DOC_GAP.md`, **đọc `.agent/steps/gap-verify.md` và chạy toàn bộ quy trình trong đó**
|
|
449
|
+
với:
|
|
450
|
+
- `FINDINGS` = mọi gap đang `Open` trong `DOC_GAP.md`
|
|
451
|
+
- `EVIDENCE_ROOT` = `{paths.specs_dir}` — spec repo của PO, **không** phải `{paths.qc_dir}`
|
|
452
|
+
- `VERDICT_FIELD` = cột `Trạng thái` + `Câu trả lời` của bảng gap
|
|
453
|
+
- `RERATE` = `on`
|
|
454
|
+
|
|
455
|
+
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
|
|
456
|
+
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
|
|
457
|
+
`[GAP VERIFY]` + cam kết cuối vào report.
|
|
458
|
+
|
|
459
|
+
> **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** —
|
|
460
|
+
> 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ó
|
|
461
|
+
> 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
|
|
462
|
+
> 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
|
|
463
|
+
> đượ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 đó
|
|
464
|
+
> 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 đó.
|
|
465
|
+
|
|
466
|
+
## Chạy lại — `DOC_GAP.md` đã tồn tại *(THÊM, không THAY)*
|
|
467
|
+
|
|
468
|
+
Chạy lại trạm này là chuyện bình thường: spec đổi thì phải phân tích lại. Nhưng `DOC_GAP.md` có
|
|
469
|
+
**hai phần khác hẳn nhau**, và chỉ một phần sinh lại được:
|
|
470
|
+
|
|
471
|
+
| Phần | Ai tạo | Sinh lại được? |
|
|
472
|
+
|---|---|:---:|
|
|
473
|
+
| Mô tả gap · phân loại · severity · UC | lệnh này | ✅ |
|
|
474
|
+
| **Cột `Trạng thái`** (`Open`/`Answered`) · **cột `Câu trả lời`** | **PO điền TAY** | ❌ **không bao giờ** |
|
|
475
|
+
| **Mã `GAP-UC{N}-{nnn}`** | lệnh này, nhưng **`.Test.md` đang trỏ vào** | ❌ đổi là phá |
|
|
476
|
+
|
|
477
|
+
**Đọc file cũ TRƯỚC khi ghi.** Với mỗi gap:
|
|
478
|
+
|
|
479
|
+
| Tình huống | Xử lý |
|
|
480
|
+
|---|---|
|
|
481
|
+
| Gap cũ, phân tích lại **vẫn thấy** | **Giữ nguyên** mã · `Trạng thái` · `Câu trả lời`. Chỉ cập nhật phần mô tả nếu spec đổi |
|
|
482
|
+
| Gap cũ, phân tích lại **không thấy nữa** | **KHÔNG xoá hàng.** `Trạng thái` → `Stale`, ghi lý do *"lần phân tích {ngày} không còn thấy"* |
|
|
483
|
+
| Gap **mới** | Cấp mã **tiếp theo** trong UC đó |
|
|
484
|
+
|
|
485
|
+
**Đánh số: CHỈ CẤP MỚI, không bao giờ tái dùng.** Mốc là **mã cao nhất từng cấp** cho UC đó — kể cả
|
|
486
|
+
khi gap mang mã ấy đã `Answered` hoặc `Stale`. Không dồn số, không lấp chỗ trống.
|
|
487
|
+
|
|
488
|
+
> **Tái dùng một mã là kịch bản tệ nhất của cả mục này.** `🚫 Block: [GAP-UC1-003]` trong một
|
|
489
|
+
> `.Test.md` cũ vẫn **đúng cú pháp**, vẫn resolve được, và giờ trỏ vào **một câu hỏi hoàn toàn khác**.
|
|
490
|
+
> Không lint nào bắt, không người nào nhìn ra. Liên kết **chết** thì còn thấy được; liên kết **trỏ
|
|
491
|
+
> sai nội dung** thì không.
|
|
492
|
+
|
|
493
|
+
**Gap `Stale` KHÔNG xoá hàng** — một `.Test.md` có thể đang trỏ vào nó. Xoá là biến `🚫 Block` thành
|
|
494
|
+
liên kết chết, và `/qc-design-test` §Guard vòng đời `🚫 Block` sẽ không phân giải được.
|
|
495
|
+
|
|
496
|
+
### Lập lại từ trắng — phải nói ra
|
|
497
|
+
|
|
498
|
+
Có ca hợp lệ: bản phân tích cũ sai hẳn, muốn bỏ. Cờ là **`--force`** (`rules/workflow.md` §Cờ bỏ qua
|
|
499
|
+
điều kiện). Không có cờ → **DỪNG** và nêu rõ cái giá:
|
|
500
|
+
|
|
501
|
+
```
|
|
502
|
+
❌ DOC_GAP.md đã tồn tại ({n} gap · {k} đã Answered).
|
|
503
|
+
Mặc định: HOÀ vào bản cũ — giữ mã gap, giữ Trạng thái/Câu trả lời của PO.
|
|
504
|
+
Muốn bỏ hẳn bản cũ, lập lại từ trắng: thêm --force
|
|
505
|
+
⚠️ --force sẽ XOÁ {k} câu trả lời của PO, và làm mọi 🚫 Block trong .Test.md trỏ sai.
|
|
506
|
+
```
|
|
507
|
+
|
|
508
|
+
Có `--force` → report **bắt buộc** khai:
|
|
509
|
+
```
|
|
510
|
+
⚠️ --force: bỏ qua luật hoà — đã xoá {k} câu trả lời của PO và {n} mã gap cũ.
|
|
511
|
+
Mọi 🚫 Block trong .Test.md của {TICKET-ID} giờ trỏ sai → chạy lại /qc-design-test cho các UC đó.
|
|
512
|
+
```
|
|
513
|
+
|
|
514
|
+
> **Vì sao hoà là MẶC ĐỊNH còn lập-lại phải xin.** Cái thường gặp phải là cái an toàn; cái phá huỷ
|
|
515
|
+
> phải nói ra — cùng lập luận `steps/qc-scope.md` dùng cho `approved`-only.
|
|
516
|
+
>
|
|
517
|
+
> **Vì sao gap ảo làm hỏng nhiều hơn một file.** §Thẩm định ở trên đã ghi: *"gap ảo … làm PO **mất
|
|
518
|
+
> tin vào cả danh sách**, và lúc đó những gap thật cũng chết theo"*. Gửi lại PO một câu hỏi **họ đã
|
|
519
|
+
> trả lời rồi** gây đúng thiệt hại đó — và nó còn tệ hơn, vì nó chứng minh hệ thống không nhớ.
|
|
520
|
+
|
|
521
|
+
## Output
|
|
522
|
+
|
|
523
|
+
Ghi **hai file** dưới `{qc_artifact_dir}` (= `{paths.qc_dir}/{TICKET-ID}/{active_platform}/`)
|
|
524
|
+
+ **một** dưới `{paths.refinement_dir}/`.
|
|
525
|
+
|
|
526
|
+
**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
|
|
527
|
+
một-file-mỗi-bước (không có file spec-breakdown / business-rules / data-flow / AC riêng):
|
|
528
|
+
|
|
529
|
+
1. **`{qc_artifact_dir}REQUIREMENT_ANALYSIS.md`** — bản phân tích hợp nhất duy nhất cho cả PRD.
|
|
530
|
+
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
|
|
531
|
+
**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
|
|
532
|
+
business-rule (`BR-xx`) → data-flow → acceptance-criteria (`AC-xx`), mỗi `BR`/`AC` map tới
|
|
533
|
+
`{UC-ID}-SC{N}` (của `.feature` nền này) sở hữu nó.
|
|
534
|
+
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
|
|
535
|
+
"Không có". *Đây là thứ chỉ trạm cấp PRD nhìn thấy được; đừng bỏ mục.*
|
|
536
|
+
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
|
|
537
|
+
các UC trong phạm vi (`{id}` · UC · điều chưa biết · owner · severity). Rỗng thì ghi
|
|
538
|
+
"Không có"; **đừng bỏ mục**.
|
|
539
|
+
2. **`{qc_artifact_dir}DOC_GAP.md`** — file gap, theo
|
|
540
|
+
`{paths.qc_skills_dir}/qa-analyst/DOC_GAP.template.md` + luật viết ở
|
|
541
|
+
`{paths.qc_skills_dir}/qa-analyst/spec-issue-reporter.md`. Bắt buộc:
|
|
542
|
+
- **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).
|
|
543
|
+
- Section **"Phạm vi phân tích"** ngay sau metadata — mỗi UC một hàng kèm `@trace.status`,
|
|
544
|
+
đã phân tích chưa, số gap. UC ngoài phạm vi ghi `⏸ Chưa xét`.
|
|
545
|
+
- Ô 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 ý**.
|
|
546
|
+
*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.*
|
|
547
|
+
- Section **"Tài liệu đầu vào đã đọc để phân tích"** đặt ngay sau metadata — liệt kê **đủ** mọi
|
|
548
|
+
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"*
|
|
549
|
+
với *"chưa đọc"*.
|
|
550
|
+
- Mức nặng nhất dùng từ **`🔴 Blocker`** (không phải `Critical`) — `/qc-run-test` đọc đúng từ này
|
|
551
|
+
để đặt *"scenario đang chờ PO"* vào sổ trace.
|
|
552
|
+
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.
|
|
553
|
+
|
|
554
|
+
`{paths.qc_dir}` là folder top-level NHÌN THẤY trong QC repo (mặc định `docs/`, **không** phải
|
|
555
|
+
`.agent/review/` ẩn) để team QC mở và xử lý output dễ dàng. Spec chính thức ở lại
|
|
556
|
+
spec submodule của PO — đừng ghi phân tích vào đó.
|
|
557
|
+
|
|
558
|
+
### Bản findings — một nguồn, hai mặt
|
|
559
|
+
|
|
560
|
+
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`
|
|
561
|
+
trước (nó là bản người đọc), rồi **render** sang `.yaml` — đừng phân tích lại lần hai.
|
|
562
|
+
|
|
563
|
+
Dùng **đúng schema của `/refine-prd`** để Review Board đọc được cả hai loại file:
|
|
564
|
+
|
|
565
|
+
```yaml
|
|
566
|
+
prd_source: "{paths.specs_dir}/{domain}/{prd-slug}/{TICKET-ID}-{prd-slug}.md"
|
|
567
|
+
ticket_id: "{TICKET-ID}"
|
|
568
|
+
platform: "{active_platform}"
|
|
569
|
+
ucs: ["{UC-ID}", "…"] # các UC TRONG phạm vi (approved) — theo thứ tự
|
|
570
|
+
ucs_skipped: ["{UC-ID}"] # UC chưa xét, kèm lý do ở DOC_GAP §Phạm vi phân tích
|
|
571
|
+
generated_at: "{ISO datetime}"
|
|
572
|
+
generated_by: "qc-analyze"
|
|
573
|
+
status: "pending_review"
|
|
574
|
+
|
|
575
|
+
findings:
|
|
576
|
+
- id: "F001"
|
|
577
|
+
lens: "QA" # LUÔN là QA — file này chỉ có một lăng kính
|
|
578
|
+
severity: "critical" # critical | major | minor ← map từ 🔴/🟠/🟡⚪ của DOC_GAP
|
|
579
|
+
section: "{section PRD/BDD chứa vấn đề}"
|
|
580
|
+
uc_id: "{UC-ID}"
|
|
581
|
+
quote: "{trích nguyên văn ≤120 ký tự từ spec tại đúng chỗ}"
|
|
582
|
+
finding: "{gap là gì}"
|
|
583
|
+
suggestion: "{cần PO/BA làm rõ điều gì}"
|
|
584
|
+
resolution_edge_cases: [] # để [] — phân tích bậc-hai là việc của /refine-prd
|
|
585
|
+
auto_fixable: false # LUÔN false — xem cảnh báo dưới
|
|
586
|
+
status: "pending"
|
|
587
|
+
applied_via: ""
|
|
588
|
+
gap_ref: "GAP-UC1-001" # trỏ ngược về hàng trong DOC_GAP.md (ID mang UC)
|
|
589
|
+
|
|
590
|
+
summary:
|
|
591
|
+
total_findings: {N}
|
|
592
|
+
by_severity: { critical: {N}, major: {N}, minor: {N} }
|
|
593
|
+
by_lens: { QA: {N} }
|
|
594
|
+
recommendation: "APPROVED_WITH_MINOR_CHANGES | NEEDS_REVISION | BLOCKED"
|
|
595
|
+
```
|
|
596
|
+
|
|
597
|
+
> **`auto_fixable` LUÔN `false`, và KHÔNG có `--resume` cho file này.**
|
|
598
|
+
>
|
|
599
|
+
> 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
|
|
600
|
+
> ở **thời điểm PRD**, sửa PRD lúc đó là sửa đúng chỗ đúng lúc.
|
|
601
|
+
>
|
|
602
|
+
> Gap của lệnh này phát hiện **sau khi BDD đã `approved` và tech-doc đã duyệt** — ở luồng song song,
|
|
603
|
+
> thường là lúc `/generate-code` đang chạy ở nhánh bên kia. Tự sửa PRD ở thời điểm đó là **sửa sau
|
|
604
|
+
> lưng cả dây chuyền**: BDD sinh từ PRD cũ, tech-doc và hợp đồng test-id §4.5.6 chốt theo BDD đó,
|
|
605
|
+
> code đang được sinh từ chúng, và sổ kết quả kiểm thử neo vào scenario của BDD đó. Đổi PRD mà không
|
|
606
|
+
> đi lại đường ấy thì mọi thứ phía sau nói dối.
|
|
607
|
+
>
|
|
608
|
+
> *(Bản trước viết tiền đề là **"sau khi code đã xong"**. Kết luận đúng, tiền đề **hết đúng** từ khi
|
|
609
|
+
> `a3a5f30` mở luồng FE ∥ QC song song — trạm này giờ chạy khi code còn chưa xong. Sửa tiền đề chứ
|
|
610
|
+
> không sửa kết luận: cái chặn không phải là **code**, mà là **BDD + tech-doc đã đóng băng**.)*
|
|
611
|
+
>
|
|
612
|
+
> Đường đúng vẫn là kênh đã có: `/report-bug` cho defect spec thật, `/propose-scenario` cho thiếu
|
|
613
|
+
> độ phủ. File `.yaml` này để **PO đọc và quyết trong một chỗ quen**, không phải để máy tự áp.
|
|
614
|
+
|
|
615
|
+
**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
|
|
616
|
+
ở **hậu tố**: `{TICKET-ID}-qa-findings.yaml` (trạm này) vs `{prd-slug}-findings.yaml`
|
|
617
|
+
(`/refine-prd`). Đừng gộp. Ghi chung sẽ phá trường `applied_to_version` mà `/refine-prd` dùng để
|
|
618
|
+
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ó
|
|
619
|
+
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ả.
|
|
620
|
+
|
|
621
|
+
---
|
|
622
|
+
|
|
623
|
+
## Self-Review *(trước khi in Report)*
|
|
624
|
+
|
|
625
|
+
Theo 3 nhóm ở `{paths.qc_skills_dir}/_shared/self-review-principles.md` — **không chép lại ở đây**.
|
|
626
|
+
|
|
627
|
+
- **Bịa:** mỗi `BR-xx`/`AC-xx` trích được về đúng dòng nào của PRD/BDD — không phải rule tôi tự
|
|
628
|
+
thêm? Mỗi gap `CONTRADICTORY` nêu được **cả hai** chỗ nói khác nhau, không phải một bên?
|
|
629
|
+
- **Nhảy bước:** đã chạy đủ 4 kỹ năng phân tích + 4 lăng kính + §Đối chiếu tài liệu kỹ thuật —
|
|
630
|
+
không bỏ lăng kính nào vì "UC này đơn giản"?
|
|
631
|
+
- **Số liệu:** `{N}` gap · `{blockers}` blocker · `{M}` BR/AC in ở report là **đếm thật trên
|
|
632
|
+
bảng vừa ghi** (`grep -cE "^\| GAP-"`), không phải áng chừng?
|
|
633
|
+
|
|
634
|
+
> **`gap-verify` và self-review bổ sung nhau, KHÔNG thay nhau.** `gap-verify` kiểm **từng
|
|
635
|
+
> finding** có sống sót qua T1–T6 (sâu, per-finding). Self-review kiểm **cả lượt chạy** có bịa /
|
|
636
|
+
> nhảy bước / đếm sai (rộng, per-run). Chạy một cái rồi bỏ cái kia là bỏ một nửa lưới.
|
|
637
|
+
>
|
|
638
|
+
> Và cả hai **không thay** Guard BR-tag ở trên — guard đó là phép so khớp cơ học, xem §Ranh giới
|
|
639
|
+
> trong file skill.
|
|
640
|
+
|
|
641
|
+
## Report
|
|
642
|
+
|
|
559
643
|
**Đọc `.agent/steps/report-footer.md`** và áp đúng khuôn footer trong đó (Status Badge ·
|
|
560
|
-
Output Artifacts · Next) cho report cuối, kèm khối bên dưới.
|
|
561
|
-
|
|
562
|
-
```
|
|
563
|
-
/qc-analyze Hoàn tất — {TICKET-ID} ({active_platform})
|
|
564
|
-
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)"}
|
|
565
|
-
Files : {paths.qc_dir}/{TICKET-ID}/{active_platform}/REQUIREMENT_ANALYSIS.md + DOC_GAP.md (11 cột)
|
|
566
|
-
{paths.refinement_dir}/{TICKET-ID}-qa-findings.yaml ← mở bằng Review Board (chuột phải)
|
|
567
|
-
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)"}
|
|
568
|
-
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
|
|
569
|
-
· đối chiếu chéo: PRD↔design-spec, bdd↔design-spec)
|
|
570
|
-
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)
|
|
571
|
-
Gaps : {N} ({blockers} blocker) — theo UC: {UC1: n · UC2: n · …}{nếu có: " · toàn PRD: {n}"}
|
|
572
|
-
← blocker là spec-defect? → /report-bug {UC-ID của hàng đó} | coverage gap → /propose-scenario {UC-ID}
|
|
573
|
-
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)
|
|
574
|
-
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
|
|
575
|
-
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)
|
|
576
|
-
SC map: {M} BR/AC map tới {K} scenario
|
|
577
|
-
Guard BR-tag: {khớp {n}/{n} | ⚠️ bổ sung {k} rule BDD đã nhắc mà phân tích bỏ sót: {danh sách}}
|
|
578
|
-
Self-review: {✅ sạch | ⚠️ {n} điểm cần chú ý — liệt kê}
|
|
579
|
-
Next : /qc-plan {TICKET-ID} {active_platform} ← rủi ro / what-if / câu hỏi cho dev
|
|
580
|
-
(giải quyết các gap 🔴 Blocker với PO/Dev trước)
|
|
581
|
-
```
|
|
582
|
-
|
|
583
|
-
> **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
|
|
584
|
-
> **và** kế hoạch test trong một lần chạy (13/14 lần đo được ở repo của họ). Ở framework đó là
|
|
585
|
-
> **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
|
|
586
|
-
> nói cho họ biết còn một bước nữa.
|
|
587
|
-
|
|
644
|
+
Output Artifacts · Next) cho report cuối, kèm khối bên dưới.
|
|
645
|
+
|
|
646
|
+
```
|
|
647
|
+
/qc-analyze Hoàn tất — {TICKET-ID} ({active_platform})
|
|
648
|
+
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)"}
|
|
649
|
+
Files : {paths.qc_dir}/{TICKET-ID}/{active_platform}/REQUIREMENT_ANALYSIS.md + DOC_GAP.md (11 cột)
|
|
650
|
+
{paths.refinement_dir}/{TICKET-ID}-qa-findings.yaml ← mở bằng Review Board (chuột phải)
|
|
651
|
+
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)"}
|
|
652
|
+
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
|
|
653
|
+
· đối chiếu chéo: PRD↔design-spec, bdd↔design-spec)
|
|
654
|
+
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)
|
|
655
|
+
Gaps : {N} ({blockers} blocker) — theo UC: {UC1: n · UC2: n · …}{nếu có: " · toàn PRD: {n}"}
|
|
656
|
+
← blocker là spec-defect? → /report-bug {UC-ID của hàng đó} | coverage gap → /propose-scenario {UC-ID}
|
|
657
|
+
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)
|
|
658
|
+
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
|
|
659
|
+
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)
|
|
660
|
+
SC map: {M} BR/AC map tới {K} scenario
|
|
661
|
+
Guard BR-tag: {khớp {n}/{n} | ⚠️ bổ sung {k} rule BDD đã nhắc mà phân tích bỏ sót: {danh sách}}
|
|
662
|
+
Self-review: {✅ sạch | ⚠️ {n} điểm cần chú ý — liệt kê}
|
|
663
|
+
Next : /qc-plan {TICKET-ID} {active_platform} ← rủi ro / what-if / câu hỏi cho dev
|
|
664
|
+
(giải quyết các gap 🔴 Blocker với PO/Dev trước)
|
|
665
|
+
```
|
|
666
|
+
|
|
667
|
+
> **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
|
|
668
|
+
> **và** kế hoạch test trong một lần chạy (13/14 lần đo được ở repo của họ). Ở framework đó là
|
|
669
|
+
> **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
|
|
670
|
+
> nói cho họ biết còn một bước nữa.
|
|
671
|
+
|