@educa-corp/sdd-framework 0.9.4 → 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 +599 -2
- package/bin/self-check.js +195 -0
- package/bin/trace-schema.json +2656 -1927
- package/core/FRAMEWORK_VERSION +1 -1
- package/core/commands/dev-gen-test.md +62 -0
- package/core/commands/generate-bdd.md +1 -0
- package/core/commands/generate-code.md +39 -2
- package/core/commands/generate-tech-docs.md +24 -5
- package/core/commands/map-testids.md +164 -7
- package/core/commands/qc-analyze.md +163 -9
- package/core/commands/qc-design-test.md +294 -2
- package/core/commands/qc-plan.md +57 -3
- package/core/commands/qc-report.md +76 -60
- package/core/commands/qc-review.md +102 -1
- package/core/commands/qc-run-test.md +194 -5
- package/core/commands/review-tech-docs.md +20 -0
- package/core/commands/validate-traces.md +17 -2
- package/core/modules/qc-playwright/stack-profile.yaml +1 -1
- package/core/rules/data-protection.md +52 -0
- package/core/rules/workflow.md +40 -0
- package/core/skills/qc/_shared/self-review-principles.md +112 -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/e2e.md +2 -2
- package/core/skills/qc/qa-runner/functional/gui-feature.md +9 -3
- package/core/skills/qc/qa-runner/functional/gui-screen.md +9 -3
- package/core/skills/qc/qa-runner/integration.md +1 -1
- package/core/skills/qc/qa-runner/non-functional.md +1 -1
- package/core/skills/spec/SKILL.md +1 -1
- package/core/steps/context-loader.md +7 -2
- package/core/steps/gap-verify.md +67 -0
- package/core/steps/qc-scope.md +67 -11
- package/core/steps/qc-stamp.md +142 -0
- package/core/steps/report-footer.md +15 -7
- package/core/templates/feature.template +1 -0
- package/core/templates/tech-design.template.md +4 -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 +7 -4
- package/docs/04-reference/trace-schema.md +38 -0
- 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 +10 -7
- 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/docs/plans/qc-surgery/00-nhat-ky.md +497 -0
- package/docs/plans/qc-surgery/01-checklist.md +92 -0
- package/docs/plans/qc-surgery/02-lo-trinh.md +266 -0
- package/docs/plans/qc-surgery/buoc/0-01-testid-attr-co-cho-o.md +157 -0
- package/docs/plans/qc-surgery/buoc/0-02-mot-nguon-cho-testid-attr.md +135 -0
- package/docs/plans/qc-surgery/buoc/0-03-skill-thoi-day-do-dom.md +167 -0
- package/docs/plans/qc-surgery/buoc/0-04-may-canh-hop-dong.md +173 -0
- package/docs/plans/qc-surgery/buoc/0-05-don-nhan-cot-va-2b.md +133 -0
- package/docs/plans/qc-surgery/buoc/0-06-hop-dong-truoc-code.md +226 -0
- package/docs/plans/qc-surgery/buoc/1-01-guard-br-tag.md +156 -0
- package/docs/plans/qc-surgery/buoc/1-02-guard-sc-coverage.md +153 -0
- package/docs/plans/qc-surgery/buoc/1-03-fail-3-nhan.md +176 -0
- package/docs/plans/qc-surgery/buoc/1-04-self-review-dung-chung.md +175 -0
- package/docs/plans/qc-surgery/buoc/1-05-spec-la-du-lieu.md +164 -0
- package/docs/plans/qc-surgery/buoc/1-06-gap-verify-du-bo.md +162 -0
- package/docs/plans/qc-surgery/buoc/README.md +85 -0
- package/docs/plans/qc-surgery/exec-d0-b1-testid-attr-header.md +147 -0
- package/docs/plans/qc-surgery/exec-d0-b2-thong-nhat-nguon-testid-attr.md +152 -0
- package/docs/plans/qc-surgery/exec-d0-b3-sua-skill-probe-dom.md +173 -0
- package/docs/plans/qc-surgery/exec-d0-b4-may-canh-4-5-6.md +168 -0
- package/docs/plans/qc-surgery/exec-d0-b5-don-nhan-lech.md +196 -0
- package/docs/plans/qc-surgery/exec-d0-b6-contract-truoc-code.md +350 -0
- package/docs/plans/qc-surgery/exec-d1-b1-guard-br-tag.md +129 -0
- package/docs/plans/qc-surgery/exec-d1-b2-guard-sc-coverage.md +159 -0
- package/docs/plans/qc-surgery/exec-d1-b3-fail-3-bucket.md +158 -0
- package/docs/plans/qc-surgery/exec-d1-b4-self-review-principles.md +145 -0
- package/docs/plans/qc-surgery/exec-d1-b5-noi-quy-spec-la-du-lieu.md +156 -0
- package/docs/plans/qc-surgery/exec-d1-b6-gap-verify-mo-rong.md +179 -0
- package/docs/plans/qc-surgery/exec-d2-b1-tach-qc-review.md +166 -0
- package/docs/plans/qc-surgery/exec-d2-b2-tach-qc-run-test-atomic.md +267 -0
- package/docs/plans/qc-surgery/exec-d2-b3-qc-automation-assess.md +198 -0
- package/docs/plans/qc-surgery/exec-d3-b1-qc-report-gate-decision.md +209 -0
- package/docs/plans/qc-surgery/exec-d4-b1-qc-design-testdata.md +146 -0
- package/docs/plans/qc-surgery/exec-d4-b2-qc-smoke-test.md +179 -0
- package/docs/plans/qc-surgery/exec-d4-b3-qc-metrics-va-lint.md +198 -0
- package/docs/plans/qc-surgery/exec-d4-b4-lint-spec-injection.md +199 -0
- package/package.json +1 -1
|
@@ -10,7 +10,9 @@ ported_from: ai-automation-qc-base
|
|
|
10
10
|
|
|
11
11
|
## Gate
|
|
12
12
|
|
|
13
|
-
*Checkpoint: **chặn
|
|
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.*
|
|
14
16
|
|
|
15
17
|
# Gate — Quy trình vào chuẩn cho mọi lệnh
|
|
16
18
|
|
|
@@ -183,14 +185,26 @@ placeholder bên dưới sẽ rỗng và lệnh sẽ đọc/ghi sai chỗ.
|
|
|
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
190
|
cả hai đều xảy ra trong im lặng, không có bước nào phía sau bắt được.
|
|
189
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
|
+
|
|
190
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ó
|
|
191
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`
|
|
192
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".
|
|
193
|
-
> Cố ý QC sớm thì thêm `--
|
|
207
|
+
> Cố ý QC sớm thì thêm `--force`, và artifact phải ghi rõ nó dựa trên BDD nháp.
|
|
194
208
|
|
|
195
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:
|
|
196
210
|
>
|
|
@@ -287,6 +301,56 @@ và ghi lại mapping — **làm cho từng UC trong `uc_list`**, và `BR`/`AC`
|
|
|
287
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
|
|
288
302
|
`@trace.verifies` cho test và ghi `qc_status` theo từng scenario.
|
|
289
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
|
+
|
|
290
354
|
## Quét gap — hai nguồn, gộp rồi mới thẩm định
|
|
291
355
|
|
|
292
356
|
Gap đến từ **hai chỗ**, và chúng bổ sung nhau chứ không thay thế:
|
|
@@ -360,9 +424,18 @@ biệt bằng cột `UC`:
|
|
|
360
424
|
gap. UC ngoài phạm vi ghi `⏸ Chưa xét`, **không bỏ khỏi bảng**.
|
|
361
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.
|
|
362
426
|
- Không bao giờ bịa câu trả lời; đánh dấu giả định là `ASSUMPTION` để PO/dev confirm.
|
|
363
|
-
- Bất kỳ `🔴 Blocker` nào còn `Open` ⇒ **UC ở cột `UC` của hàng đó** chưa sẵn sàng
|
|
364
|
-
|
|
365
|
-
|
|
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ế đó.*
|
|
366
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
|
|
367
440
|
trong spec chính thức — `AMBIGUOUS` / `CONTRADICTORY` / `MISSING` trong PRD/BDD — phải tới
|
|
368
441
|
PO qua feedback flow, không chỉ nằm trong `DOC_GAP.md`: tạo `/report-bug {UC-ID} {desc}`
|
|
@@ -390,6 +463,61 @@ nó bị loại. Cập nhật `Tổng số gap` + bảng ưu tiên sau khi áp v
|
|
|
390
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 đó
|
|
391
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 đó.
|
|
392
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
|
+
|
|
393
521
|
## Output
|
|
394
522
|
|
|
395
523
|
Ghi **hai file** dưới `{qc_artifact_dir}` (= `{paths.qc_dir}/{TICKET-ID}/{active_platform}/`)
|
|
@@ -471,9 +599,15 @@ summary:
|
|
|
471
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
|
|
472
600
|
> ở **thời điểm PRD**, sửa PRD lúc đó là sửa đúng chỗ đúng lúc.
|
|
473
601
|
>
|
|
474
|
-
> Gap của lệnh này phát hiện **sau khi
|
|
475
|
-
>
|
|
476
|
-
>
|
|
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**.)*
|
|
477
611
|
>
|
|
478
612
|
> Đường đúng vẫn là kênh đã có: `/report-bug` cho defect spec thật, `/propose-scenario` cho thiếu
|
|
479
613
|
> độ phủ. File `.yaml` này để **PO đọc và quyết trong một chỗ quen**, không phải để máy tự áp.
|
|
@@ -486,6 +620,24 @@ người sửa sau lưng, mỗi lần chạy đều quét lại toàn bộ kèm
|
|
|
486
620
|
|
|
487
621
|
---
|
|
488
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
|
+
|
|
489
641
|
## Report
|
|
490
642
|
|
|
491
643
|
**Đọc `.agent/steps/report-footer.md`** và áp đúng khuôn footer trong đó (Status Badge ·
|
|
@@ -506,6 +658,8 @@ Chéo UC: {X} mâu thuẫn giữa các UC của cùng PRD (đã ghi vào REQUIRE
|
|
|
506
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
|
|
507
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)
|
|
508
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ê}
|
|
509
663
|
Next : /qc-plan {TICKET-ID} {active_platform} ← rủi ro / what-if / câu hỏi cho dev
|
|
510
664
|
(giải quyết các gap 🔴 Blocker với PO/Dev trước)
|
|
511
665
|
```
|
|
@@ -10,7 +10,9 @@ ported_from: ai-automation-qc-base
|
|
|
10
10
|
|
|
11
11
|
## Gate
|
|
12
12
|
|
|
13
|
-
*Checkpoint: **chặn
|
|
13
|
+
*Checkpoint: **chặn CỨNG** — ghi đè `*.Test.md` đã qua cổng HITL `/qc-review` → mất `Status` đã duyệt, `Expected Result` đã sửa theo finding, dấu 🚫 Block vừa gỡ; và ĐÁNH SỐ LẠI `TC_<FEATURE>_NNN` mà `REVIEW_<FEATURE>.md` đang trỏ vào. `--yes` KHÔNG bỏ qua được (gate Bước 3a).*
|
|
14
|
+
|
|
15
|
+
*Mức cứng chỉ áp khi file `.Test.md` **đã tồn tại**. Lần thiết kế đầu không ghi đè gì, đi thẳng. Xem §Chạy lại.*
|
|
14
16
|
|
|
15
17
|
# Gate — Quy trình vào chuẩn cho mọi lệnh
|
|
16
18
|
|
|
@@ -181,10 +183,22 @@ placeholder bên dưới sẽ rỗng và lệnh sẽ đọc/ghi sai chỗ.
|
|
|
181
183
|
rồi mới tiếp tục phần bên dưới.
|
|
182
184
|
|
|
183
185
|
Nó chốt bốn thứ mà mọi trạm QC đều cần: `TICKET-ID` · `active_platform` ·
|
|
184
|
-
`qc_artifact_dir` · `uc_list` (kèm trạng thái BDD từng UC, và cờ `--
|
|
186
|
+
`qc_artifact_dir` · `uc_list` (kèm trạng thái BDD từng UC, và cờ `--force`).
|
|
185
187
|
Bỏ qua thì artifact QC ghi vào **sai thư mục** và `qc_status` ghi vào **sai sổ trace** —
|
|
186
188
|
cả hai đều xảy ra trong im lặng, không có bước nào phía sau bắt được.
|
|
187
189
|
|
|
190
|
+
---
|
|
191
|
+
|
|
192
|
+
## Stamp phiên bản nguồn
|
|
193
|
+
|
|
194
|
+
**BẮT BUỘC — đọc `.agent/steps/qc-stamp.md` và thực thi phần áp cho lệnh này**,
|
|
195
|
+
rồi mới tiếp tục phần bên dưới.
|
|
196
|
+
|
|
197
|
+
Nó có **hai vế**: §1 **ghi** khối `Nguồn & phiên bản` vào artifact lệnh này sinh ra ·
|
|
198
|
+
§2 **so** stamp của artifact lệnh này ĐỌC với version hiện tại của spec.
|
|
199
|
+
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
|
|
200
|
+
đọ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**.
|
|
201
|
+
|
|
188
202
|
> **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
|
|
189
203
|
> 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
|
|
190
204
|
> artifact nằm chung ở `{qc_artifact_dir}` cấp PRD, không còn một thư mục mỗi UC.
|
|
@@ -194,6 +208,58 @@ cả hai đều xảy ra trong im lặng, không có bước nào phía sau bắ
|
|
|
194
208
|
|
|
195
209
|
---
|
|
196
210
|
|
|
211
|
+
## Guard — tiền đề *(chạy NGAY SAU §Phạm vi QC, TRƯỚC mọi việc khác của lệnh)*
|
|
212
|
+
|
|
213
|
+
Trạm này là **trạm 3**. Nó **tiêu thụ** output của trạm 1 và trạm 2 — không tự sinh lại được.
|
|
214
|
+
Kiểm sự tồn tại của cả ba file dưới `{qc_artifact_dir}`:
|
|
215
|
+
|
|
216
|
+
| File | Do lệnh nào sinh | Trạm này dùng để |
|
|
217
|
+
|---|---|---|
|
|
218
|
+
| `REQUIREMENT_ANALYSIS.md` | `/qc-analyze` | neo `BR-xx`/`AC-xx` cho trường `Trace:` của mỗi TC |
|
|
219
|
+
| `DOC_GAP.md` | `/qc-analyze` | gắn `🚫 Block` cho TC bị gap chặn |
|
|
220
|
+
| `TEST_PLAN.md` | `/qc-plan` | độ sâu theo rủi ro (P0/P1) · layer trong scope · entry criteria |
|
|
221
|
+
|
|
222
|
+
**Thiếu bất kỳ file nào → DỪNG.** Không hỏi Y/N, không cảnh báo rồi đi tiếp:
|
|
223
|
+
|
|
224
|
+
```
|
|
225
|
+
❌ {TICKET-ID} ({active_platform}): thiếu đầu vào của trạm 3.
|
|
226
|
+
Không có: {danh sách file thiếu}
|
|
227
|
+
Chạy trước: /qc-analyze {TICKET-ID} {active_platform}
|
|
228
|
+
rồi: /qc-plan {TICKET-ID} {active_platform}
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
**Đủ cả ba → im lặng, đi tiếp.** Guard này là **điều kiện vào cửa**, không phải phép đo: "đủ file"
|
|
232
|
+
không phải một phát hiện, nên không in dòng nào. *(Khác `Guard BR-tag` và `Guard SC coverage` —
|
|
233
|
+
hai cái đó là phép ĐẾM, con số của chúng có giá trị ngay cả khi sạch, nên chúng luôn in.)*
|
|
234
|
+
|
|
235
|
+
> **Vì sao DỪNG chứ không cảnh báo rồi chạy.** Guard duy nhất còn lại của trạm này —
|
|
236
|
+
> `Guard SC coverage` — đối chiếu TC với `.feature`, mà `.feature` ở spec repo thì **luôn có mặt**,
|
|
237
|
+
> không mất theo khi trạm 1–2 chưa chạy. Nên nó vẫn in `khớp K/K` và lần chạy thiếu đầu vào
|
|
238
|
+
> **không phân biệt được** với một lần chạy đúng.
|
|
239
|
+
>
|
|
240
|
+
> Thiếu `DOC_GAP.md` là ca đắt nhất: TC bị gap chặn **trông y hệt** TC bình thường (không có dấu
|
|
241
|
+
> `🚫 Block` nào), nên `/qc-run-test` chạy nó, thấy đỏ, và `/qc-report` phân loại thành *product-gap*
|
|
242
|
+
> rồi in một `/report-bug` sẵn-chạy. Lỗi đi **ra khỏi đội QC** thành bug gửi PO — cho một hành vi
|
|
243
|
+
> mà spec chưa bao giờ định nghĩa. Đây là **báo cáo sai**, cùng loại với việc giữ một `pass` đã hết
|
|
244
|
+
> hiệu lực (`rules/workflow.md` §*"Làm mất hiệu lực ≠ ghi đè"*).
|
|
245
|
+
>
|
|
246
|
+
> **Vì sao DỪNG chứ không hỏi Y/N.** Một cổng chỉ chặn được khi có người ngồi đó thì ở chế độ
|
|
247
|
+
> headless nó không phải cổng, nó là **treo** — cùng bài học với `steps/qc-scope.md` §2.
|
|
248
|
+
>
|
|
249
|
+
> **Vì sao `--yes` KHÔNG bỏ qua được.** `--yes` nghĩa *"tôi không ngồi đây để trả lời"*, không phải
|
|
250
|
+
> *"tôi chấp nhận thiết kế test không có phân tích gap"*. Gộp hai nghĩa là để một lần chạy headless
|
|
251
|
+
> âm thầm sinh ra một bộ test case thiếu mọi dấu chặn.
|
|
252
|
+
>
|
|
253
|
+
> **Vì sao cả ba file đều bắt buộc, không miễn trừ `TEST_PLAN.md`.** Không có luồng hợp lệ nào có
|
|
254
|
+
> file 1–2 mà thiếu file 3: `Next` của `/qc-analyze` chính là `/qc-plan`. Miễn trừ nó là mở một
|
|
255
|
+
> đường tắt không ai xin.
|
|
256
|
+
>
|
|
257
|
+
> **Chỉ kiểm SỰ TỒN TẠI, không kiểm nội dung hay độ tươi.** Ba file này có còn khớp spec hiện tại
|
|
258
|
+
> không là một câu hỏi khác, và nó cần một cơ chế khác (đóng dấu version nguồn). Trộn hai việc vào
|
|
259
|
+
> một guard thì guard này không bao giờ landing được.
|
|
260
|
+
|
|
261
|
+
---
|
|
262
|
+
|
|
197
263
|
## Cờ — chọn tầng nào, tách mịn đến đâu
|
|
198
264
|
|
|
199
265
|
| Cờ | Ghi file | Nhóm |
|
|
@@ -314,6 +380,209 @@ vẫn pass/fail, nhưng kết quả không vào được sổ và không ai bi
|
|
|
314
380
|
|
|
315
381
|
Cuối file: **Trace matrix** (BR ↔ TC ↔ SC) + **danh sách TC bị block** — cả hai dạng danh sách.
|
|
316
382
|
|
|
383
|
+
## Guard — SC coverage *(phép ĐẾM cơ học, chạy SAU khi ghi file, TRƯỚC CHECKPOINT)*
|
|
384
|
+
|
|
385
|
+
Dòng `Trace:` ở report cuối đã đòi con số `{K}/{total}` từ trước. Guard này là **phép tính sinh
|
|
386
|
+
ra con số đó**, và là **hệ quả khi `K < total`** — trước đây có số mà không có phép tính nào
|
|
387
|
+
đứng sau, nên nó là ước lượng, và `K < total` không dẫn tới việc gì.
|
|
388
|
+
|
|
389
|
+
### Ba bước
|
|
390
|
+
|
|
391
|
+
1. **Thu SC** — mọi `@trace.scenario` trong `.feature` của **UC đang chạy** (`{UC-ID}`, đúng
|
|
392
|
+
`active_platform`) — **KHÔNG phải `uc_list`.**
|
|
393
|
+
|
|
394
|
+
`uc_list` là mọi UC approved của **cả PRD**; trạm này chạy **per-UC** (§Phạm vi QC), nên lấy
|
|
395
|
+
`uc_list` làm mẫu số là ép viết TC cho UC **không ai yêu cầu** — bằng dữ liệu đã lọc bỏ phần
|
|
396
|
+
của chúng ở Gate (*"lọc theo cột `UC` để lấy phần của UC này"*), tức là **viết mù**.
|
|
397
|
+
|
|
398
|
+
*Trạm 1 `/qc-analyze` dùng `uc_list` là **đúng** — nó cấp PRD, và mâu thuẫn chéo UC chỉ lộ ra
|
|
399
|
+
khi đọc cùng lúc. **Đừng copy mẫu số giữa hai trạm khác tầng.** Phép kiểm một câu: mẫu số của
|
|
400
|
+
một guard phải khớp **phạm vi mà lệnh đó được gọi**.*
|
|
401
|
+
|
|
402
|
+
**Không cần lọc `⏸ chưa xét` ở đây nữa:** `qc-scope` §4b đã chặn UC target chưa approved từ
|
|
403
|
+
trước khi tới bước này. Chạy được tới đây nghĩa là target hoặc đã `approved`, hoặc người dùng
|
|
404
|
+
đã nêu `--force` tường minh (và artifact đang mang dấu *"dựa trên BDD nháp"*).
|
|
405
|
+
2. **Thu V** — mọi `@trace.verifies` trong **MỌI** `*.Test.md` dưới `{qc_artifact_dir}test-cases/`
|
|
406
|
+
— **không chỉ file vừa ghi** — rồi lọc lấy giá trị bắt đầu bằng `{UC-ID}-SC`.
|
|
407
|
+
|
|
408
|
+
*Thư mục `test-cases/` dùng chung cho **cả PRD** nên phải lọc theo UC. Và lệnh này có **ba chế
|
|
409
|
+
độ ghi** (§Cờ), hai trong ba chỉ ghi **một nửa**: `--api` chạy sau khi file giao diện đã tồn tại
|
|
410
|
+
là **chuyện thường** (§B12 ngay dưới bảng Cờ). Chỉ đếm file "vừa ghi" thì lần chạy `--api` thấy
|
|
411
|
+
độ phủ ≈ 0, rồi luật "viết bù TC ngay" **nhân bản toàn bộ TC giao diện vào file API** — phá đúng
|
|
412
|
+
ranh giới hai-file mà §B12 dựng lên.*
|
|
413
|
+
|
|
414
|
+
**Tiền tố lọc phải gồm cả `-SC`.** `{UC-ID}-SC` chứ **không** phải `{UC-ID}`:
|
|
415
|
+
`FT-001-UC1-SC` không khớp `FT-001-UC11-SC3`, còn `FT-001-UC1` thì có. Một PRD tới UC thứ 11
|
|
416
|
+
là đủ để phép lọc sai **trong im lặng**.
|
|
417
|
+
|
|
418
|
+
*Quét cả thư mục chứ không đoán theo tên file: tên file mang `<FEATURE>`, **không** mang UC —
|
|
419
|
+
`@trace.verifies` là chỗ duy nhất nói TC thuộc UC nào (§Output).*
|
|
420
|
+
3. **Đếm** — mỗi SC ∈ tập ở bước 1 phải có **≥ 1** TC trỏ tới.
|
|
421
|
+
|
|
422
|
+
### Xử lý
|
|
423
|
+
|
|
424
|
+
| Kết quả | Làm gì |
|
|
425
|
+
|---|---|
|
|
426
|
+
| Mọi SC đều có ≥1 TC | in `Guard SC coverage: khớp {K}/{K}` |
|
|
427
|
+
| Có SC chưa phủ | **viết bù TC ngay** — vào file đúng theo §Câu hỏi phân file, xem luật định tuyến dưới đây — rồi in `⚠️ Guard SC coverage: {K}/{total} — đã bù {m} SC: {danh sách}` |
|
|
428
|
+
|
|
429
|
+
**TC bù đi vào file nào — theo §Câu hỏi phân file, KHÔNG mặc định vào file của chế độ đang chạy.**
|
|
430
|
+
|
|
431
|
+
Hỏi từng SC chưa phủ: *"TC cho SC này verify được mà **không cần UI** không?"*
|
|
432
|
+
|
|
433
|
+
| Trả lời | Chế độ đang chạy | Làm gì |
|
|
434
|
+
|---|---|---|
|
|
435
|
+
| **Có** (không cần UI) | `--api` hoặc `--all` | bù vào **file API** — xong |
|
|
436
|
+
| **Không** (cần UI) | *(không cờ)* hoặc `--all` | bù vào **file giao diện** — xong |
|
|
437
|
+
| **Không** (cần UI) | **`--api`** | **KHÔNG bù vào file API.** SC vẫn tính là **chưa phủ**; in thêm dòng chỉ đường (dưới) |
|
|
438
|
+
|
|
439
|
+
```
|
|
440
|
+
⚠️ {n} SC cần UI, chưa có TC ở file giao diện — KHÔNG bù vào file API (§Câu hỏi phân file).
|
|
441
|
+
Chạy: /qc-design-test {UC-ID} ← không cờ, để bù đúng chỗ
|
|
442
|
+
SC: {danh sách}
|
|
443
|
+
```
|
|
444
|
+
|
|
445
|
+
> **Đây KHÔNG phải "bỏ trống có lý do".** Phân biệt bằng một câu: đường thoát làm SC **được tính là
|
|
446
|
+
> đã phủ**; luật này để SC **vẫn nằm trong số chưa phủ** — `{K}/{total}` không đổi, dòng ⚠️ vẫn in,
|
|
447
|
+
> guard vẫn chưa sạch. Nó chỉ đổi **chỗ ghi TC**, không đổi **phép đếm**.
|
|
448
|
+
>
|
|
449
|
+
> Và nó **không** cho agent một câu-lý-do-cho-qua: điều kiện là một phép so cơ học (*"cần UI không?"*
|
|
450
|
+
> — đúng Bước 2 của `shared/skill-decision-tree.md`), không phải một nhận định tự do. Ghi *"SC này
|
|
451
|
+
> phức tạp"*, *"tương tự SC2"* thì **không** rơi vào ô nào của bảng trên.
|
|
452
|
+
>
|
|
453
|
+
> **Vì sao không cứ bù vào file đang mở cho gọn.** File API được `/qc-run-test` đọc bằng lane API.
|
|
454
|
+
> Một TC cần UI nằm ở đó **không chạy nổi** — và nó sẽ đỏ dưới dạng *script-bug* hoặc *product-gap*,
|
|
455
|
+
> không ai truy ngược về một quyết định ghi file ở phase thiết kế.
|
|
456
|
+
|
|
457
|
+
**Không có đường "bỏ trống có lý do".** Đây là chỗ dễ làm sai nhất, và quy ước ở §Conventions
|
|
458
|
+
đã trả lời: *"Một TC bị block bởi gap **vẫn viết đủ** + `🚫 Block: [GAP-UC{N}-{nnn}](../DOC_GAP.md)`"*.
|
|
459
|
+
Nghĩa là **gap không phải cái cớ để không viết TC** — nó là thứ được **ghi vào TC**. SC bị chặn
|
|
460
|
+
vẫn có TC, vẫn được đếm là đã phủ.
|
|
461
|
+
|
|
462
|
+
Nên chỉ còn đúng hai trạng thái, và cả hai đều không cho phép bỏ trống:
|
|
463
|
+
|
|
464
|
+
- SC **của UC đang chạy** → phải có TC (bị gap chặn thì TC mang dấu `🚫 Block`). Đây là **toàn bộ**
|
|
465
|
+
mẫu số — bước 1 không lấy SC của UC nào khác.
|
|
466
|
+
- SC **của UC khác** → không thuộc lần chạy này, không tính vào mẫu số. *(Muốn phủ chúng thì chạy
|
|
467
|
+
`/qc-design-test` cho UC đó — đừng viết TC của chúng ở đây.)*
|
|
468
|
+
|
|
469
|
+
Nếu bạn thấy một SC "không thể viết TC" mà không thuộc hai loại trên, thì **đó là một gap** —
|
|
470
|
+
mở gap trong `DOC_GAP.md`, viết TC kèm `🚫 Block` trỏ tới nó. Đừng viết một câu lý do rồi đi
|
|
471
|
+
tiếp: guard viết lỏng thì lần sau sẽ có một câu lý do cho qua, và phép đếm mất nghĩa.
|
|
472
|
+
|
|
473
|
+
*(Ca "SC cần UI mà đang chạy `--api`" **không** phải trạng thái thứ ba: SC đó vẫn ở nhóm thứ nhất,
|
|
474
|
+
vẫn tính vào mẫu số, vẫn chưa phủ. Chỉ **chỗ ghi TC** bị hoãn — xem luật định tuyến ở §Xử lý.)*
|
|
475
|
+
|
|
476
|
+
**In dòng `Guard SC coverage:` kể cả khi sạch** — guard im lặng khi sạch là guard không ai biết
|
|
477
|
+
nó tồn tại, và không ai phát hiện được khi nó chết.
|
|
478
|
+
|
|
479
|
+
> **Vì sao đếm ở đây mà không đợi báo cáo cuối.** `/qc-report` **sẽ** tính **design coverage** bằng
|
|
480
|
+
> **đúng phép đếm này** — **Đợt 3, CHƯA TRIỂN KHAI** (`docs/plans/qc-surgery/01-checklist.md`, phụ
|
|
481
|
+
> thuộc cứng vào `d2-b2`). Khác nhau ở thời điểm: guard đếm **lúc thiết kế** — còn kịp viết bù; báo
|
|
482
|
+
> cáo đếm **ở cuối** — chỉ còn kịp báo. Phát hiện "design coverage 68%" ở phút cuối là lúc không còn
|
|
483
|
+
> thời gian viết bù 32%.
|
|
484
|
+
>
|
|
485
|
+
> **Tới khi Đợt 3 có, guard này là lớp đếm DUY NHẤT — đừng dựa vào một lớp thứ hai chưa tồn tại.**
|
|
486
|
+
> *(Bản trước viết "sẽ tính" ở thì hiện tại, không nêu trạng thái. Một lời hứa không có trạng thái sẽ
|
|
487
|
+
> được đọc như một sự thật — và tệ nhất là khi nó được dùng để biện minh cho việc không đếm ở chỗ khác.)*
|
|
488
|
+
>
|
|
489
|
+
> **Vì sao "chưa có TC" khác "có TC nhưng chưa chạy".** Hai trạng thái này dẫn tới hai việc khác
|
|
490
|
+
> nhau hoàn toàn — viết test, so với chạy test. Nhưng nhìn vào sổ trace thì giống nhau: cả hai
|
|
491
|
+
> đều là `qc_status = not_run`. Guard này là chỗ duy nhất phân biệt được.
|
|
492
|
+
|
|
493
|
+
## Chạy lại — `.Test.md` đã tồn tại *(GIỮ, không sinh lại từ trắng)*
|
|
494
|
+
|
|
495
|
+
File `.Test.md` đi qua **cổng HITL `/qc-review`**. Bốn thứ trong đó **không sinh lại được**:
|
|
496
|
+
|
|
497
|
+
| Mất gì | Vì sao |
|
|
498
|
+
|---|---|
|
|
499
|
+
| `Status` đổi sau review | **kết luận của người**, không suy từ spec |
|
|
500
|
+
| `Expected Result` sửa theo finding | finding nằm ở `REVIEW_<FEATURE>.md` — **lệnh này không đọc file đó** |
|
|
501
|
+
| Dấu `🚫 Block` vừa gỡ | phụ thuộc ô `Câu trả lời` của `DOC_GAP.md` (xem §Guard vòng đời 🚫 Block) |
|
|
502
|
+
| Đánh số `TC_<FEATURE>_NNN` | **`REVIEW_<FEATURE>.md` đang trỏ vào các số đó**, và nó nằm cùng thư mục |
|
|
503
|
+
|
|
504
|
+
**Đọc file cũ TRƯỚC khi ghi.** Với mỗi TC:
|
|
505
|
+
|
|
506
|
+
| Tình huống | Xử lý |
|
|
507
|
+
|---|---|
|
|
508
|
+
| TC cũ, spec **không đổi** | **Giữ nguyên** — số · `Status` · `Expected Result` đã sửa |
|
|
509
|
+
| TC cũ, spec **đổi** | Cập nhật **nội dung**; giữ **số** và `Status`, thêm ⚠️ để `/qc-review` soát lại |
|
|
510
|
+
| TC **mới** | Cấp số **tiếp theo** — không dồn, không tái dùng |
|
|
511
|
+
| TC không còn ứng với SC nào | **KHÔNG xoá** → `Status: Obsolete`, ghi lý do |
|
|
512
|
+
|
|
513
|
+
> **`Obsolete` chứ không xoá** — cùng luật `Stale` của `/qc-analyze` §Chạy lại: `REVIEW_<FEATURE>.md`
|
|
514
|
+
> đang trỏ vào số đó, xoá hàng là biến biên bản soát thành liên kết chết.
|
|
515
|
+
>
|
|
516
|
+
> **§duplicate-check KHÔNG phải lưới cho ca này.** Nó chống **viết trùng** (*"grep trước khi viết"*),
|
|
517
|
+
> không chống **ghi đè**. Hai chuyện khác nhau, và tên nghe giống nhau đủ để tưởng đã có người lo.
|
|
518
|
+
|
|
519
|
+
### Lập lại từ trắng — phải nói ra
|
|
520
|
+
|
|
521
|
+
```
|
|
522
|
+
❌ {n} file .Test.md đã tồn tại ({k} TC có Status khác Draft — đã qua review).
|
|
523
|
+
Mặc định: GIỮ số + Status + Expected đã sửa, chỉ cập nhật nội dung theo spec mới.
|
|
524
|
+
Muốn bỏ hẳn và thiết kế lại từ trắng: thêm --force
|
|
525
|
+
⚠️ --force sẽ XOÁ {k} kết quả review và làm REVIEW_<FEATURE>.md trỏ sai số TC.
|
|
526
|
+
```
|
|
527
|
+
|
|
528
|
+
---
|
|
529
|
+
|
|
530
|
+
## Guard — vòng đời `🚫 Block` *(phép so cơ học, chạy SAU khi ghi file, TRƯỚC CHECKPOINT)*
|
|
531
|
+
|
|
532
|
+
`🚫 Block` có bước **mở** (§Conventions: TC chạm gap thì mang dấu) và một quy trình **đóng** viết
|
|
533
|
+
sẵn ở `{paths.qc_skills_dir}/qa-designer/shared/tc-metadata-format.md` §*Quy trình khi gap được giải
|
|
534
|
+
quyết (Answered)*. Bước đóng đó **chưa lệnh nào gọi** — nên dấu chặn chỉ dán vào, không bao giờ gỡ ra.
|
|
535
|
+
|
|
536
|
+
Một TC mang `🚫 Block` là một TC có **Expected Result dựa trên giả định chưa ai xác nhận**. Nó nằm
|
|
537
|
+
trong thư mục dùng chung, được `Guard SC coverage` đếm là **đã phủ**, và `/qc-run-test` sẽ nhặt lên.
|
|
538
|
+
|
|
539
|
+
> **Vì sao stamp phiên bản (§Stamp phiên bản nguồn) KHÔNG phủ ca này.** Gap chuyển `Open → Answered`
|
|
540
|
+
> là một **ô trong `DOC_GAP.md`** — nó **không bump version nào cả**. Mọi drift detector của framework
|
|
541
|
+
> so **nhãn version**; thay đổi trạng thái nằm *bên trong* một tài liệu đi vòng qua tất cả.
|
|
542
|
+
|
|
543
|
+
### Bốn bước, thuần so chuỗi
|
|
544
|
+
|
|
545
|
+
1. **Thu B** — mọi `GAP-ID` xuất hiện trong dòng `🚫 Block:` của các `*.Test.md` của UC này.
|
|
546
|
+
2. **Thu A** — mọi `GAP-ID` có `Trạng thái = Answered` trong `DOC_GAP.md` (lọc theo cột `UC`).
|
|
547
|
+
3. **So** — `A ∩ B` = gap đã trả lời mà TC vẫn mang dấu chặn.
|
|
548
|
+
4. **Xử lý:**
|
|
549
|
+
|
|
550
|
+
| Kết quả | Làm gì |
|
|
551
|
+
|---|---|
|
|
552
|
+
| `A ∩ B` rỗng | in `Guard 🚫 Block: {n} dấu đang mở, 0 cần gỡ` |
|
|
553
|
+
| Có phần tử, **ô `Câu trả lời` ĐÃ điền** | **GỠ NGAY** theo 4 bước của skill: bỏ dấu `🚫 Block` · cập nhật `Expected Result` theo câu trả lời thật · nếu answer đổi scope thì tách/thêm TC. Rồi in:<br/>`🔓 Guard 🚫 Block: gỡ {k} dấu (gap đã Answered): {danh sách GAP-ID}` |
|
|
554
|
+
| Có phần tử, **ô `Câu trả lời` TRỐNG** | **KHÔNG gỡ.** In:<br/>`⚠️ Guard 🚫 Block: {GAP-ID} = Answered nhưng ô "Câu trả lời" trống — không gỡ được, hỏi lại PO.` |
|
|
555
|
+
|
|
556
|
+
**Guard TỰ SỬA, không chỉ tự báo** — cùng luật `Guard BR-tag` của `/qc-analyze` đã chốt: *"In cảnh
|
|
557
|
+
báo rồi để người đi lấp là thêm một dòng nữa để bỏ qua."*
|
|
558
|
+
|
|
559
|
+
**Nhưng ô `Câu trả lời` trống thì DỪNG, không đoán.** Gỡ dấu chặn mà không có câu trả lời thật là
|
|
560
|
+
**biến một giả định thành sự thật trong im lặng** — và `Expected Result` sai sẽ fail lúc chạy, rồi
|
|
561
|
+
`/qc-report` phân loại *product-gap* và in một `/report-bug`. Lúc đó một lỗ hổng **tài liệu** đã đi ra
|
|
562
|
+
ngoài đội QC thành **phiếu lỗi sản phẩm** gửi PO.
|
|
563
|
+
|
|
564
|
+
**In dòng `Guard 🚫 Block:` kể cả khi sạch** — cùng lý do với hai guard kia.
|
|
565
|
+
|
|
566
|
+
---
|
|
567
|
+
|
|
568
|
+
## UC đang Blocked — nói ra, KHÔNG chặn
|
|
569
|
+
|
|
570
|
+
`TEST_PLAN.md` §5 ghi `Ready`/`Blocked` cho mỗi UC (guard tiền đề đã ép file này phải có). Đọc trạng
|
|
571
|
+
thái của UC đang chạy. **`Blocked` là mức ƯU TIÊN, không phải lệnh cấm** — vẫn thiết kế bình thường,
|
|
572
|
+
chỉ in thêm một dòng ở report:
|
|
573
|
+
|
|
574
|
+
```
|
|
575
|
+
⚠️ {UC-ID} đang Blocked bởi {n} gap 🔴 — TC chạm chúng mang dấu 🚫 Block, chưa chạy được.
|
|
576
|
+
Gỡ chặn: trả lời {danh sách GAP-ID} với PO → chạy lại lệnh này để tự gỡ dấu.
|
|
577
|
+
```
|
|
578
|
+
|
|
579
|
+
> **Vì sao không chặn** *(G66)*. `/qc-analyze` nói *"chưa sẵn sàng"* nghĩa là **chưa sẵn sàng để
|
|
580
|
+
> nghiệm thu**, không phải *"chưa được thiết kế"* — và §Conventions của chính lệnh này đã trả lời:
|
|
581
|
+
> *"TC bị block bởi gap **vẫn viết đủ**"*. Chặn ở đây là giết cơ chế `🚫 Block`, thứ được dựng kỹ tới
|
|
582
|
+
> mức có mã gap mang UC, liên kết ngược `../DOC_GAP.md`, và một dòng riêng trong report.
|
|
583
|
+
>
|
|
584
|
+
> Cái bị chặn là **chạy test**, không phải **viết test**.
|
|
585
|
+
|
|
317
586
|
## Output
|
|
318
587
|
|
|
319
588
|
Ghi dưới `{qc_artifact_dir}test-cases/`
|
|
@@ -326,6 +595,21 @@ TC thuộc UC nào.
|
|
|
326
595
|
|
|
327
596
|
`🚫 Block` trỏ `../DOC_GAP.md` — lên một cấp, vì file gap ở thư mục cha của `test-cases/`.
|
|
328
597
|
|
|
598
|
+
## Self-Review *(trước khi in Report)*
|
|
599
|
+
|
|
600
|
+
Theo 3 nhóm ở `{paths.qc_skills_dir}/_shared/self-review-principles.md` — **không chép lại ở đây**.
|
|
601
|
+
|
|
602
|
+
- **Bịa:** mỗi TC kiểm một hành vi **spec có nêu** — không phải hành vi tôi cho là hợp lý? Mỗi
|
|
603
|
+
`Expected` là **giá trị cụ thể** (*"hiển thị text 'Tên lớp: Toán 6A'"*), không phải *"hiển thị
|
|
604
|
+
đúng"* / *"hoạt động bình thường"*?
|
|
605
|
+
- **Nhảy bước:** đã áp luật ATOMIC cho **mọi** TC (không chỉ vài TC đầu), và đã chạy
|
|
606
|
+
§duplicate-check trước khi thêm TC mới?
|
|
607
|
+
- **Số liệu:** `{n}` TC mỗi file = `grep -cE "^#{2,4} *TC_"` thật? Các con số phân nhóm (GUI /
|
|
608
|
+
Validation / Functional / …) cộng lại đúng bằng tổng TC?
|
|
609
|
+
|
|
610
|
+
> Guard SC coverage ở trên là **phép đếm cơ học**, không phải self-review — nó đối chiếu với
|
|
611
|
+
> `.feature`, một nguồn khác. Đừng coi self-review đã bao nó. Xem §Ranh giới trong file skill.
|
|
612
|
+
|
|
329
613
|
## Report
|
|
330
614
|
|
|
331
615
|
**Đọc `.agent/steps/report-footer.md`** và áp đúng khuôn footer trong đó (Status Badge ·
|
|
@@ -340,6 +624,14 @@ Nhóm : GUI {a} · Validation {b} · Functional {c} · Integration {d} · NFR {e
|
|
|
340
624
|
{nếu file API: "Endpoint {g} · Integration API/DB/Kafka {h}"}
|
|
341
625
|
Trùng: {k} TC bỏ vì trùng ({j} trùng chéo UC — trỏ trace về UC nguồn thay vì viết lại)
|
|
342
626
|
Block: {blocked} TC bị chặn bởi gap — theo UC: {UC1: n · UC2: n}
|
|
627
|
+
{nếu UC đang Blocked: "⚠️ {UC-ID} đang Blocked bởi {n} gap 🔴 — trả lời {GAP-ID} với PO
|
|
628
|
+
rồi chạy lại lệnh này để tự gỡ dấu."}
|
|
629
|
+
Guard 🚫 Block: {{n} dấu đang mở, 0 cần gỡ | 🔓 gỡ {k} dấu (gap đã Answered): {danh sách}
|
|
630
|
+
| ⚠️ {GAP-ID} = Answered nhưng ô "Câu trả lời" trống — không gỡ được, hỏi lại PO}
|
|
343
631
|
Trace: {N} TC map tới {K}/{total} scenario của {UC-ID}
|
|
632
|
+
Guard SC coverage: {khớp {K}/{K} | ⚠️ {K}/{total} — đã bù {m} SC: {danh sách SC}}
|
|
633
|
+
{nếu có SC cần UI mà đang chạy --api: "⚠️ {n} SC cần UI chưa có TC ở file giao diện —
|
|
634
|
+
KHÔNG bù vào file API. Chạy: /qc-design-test {UC-ID} (không cờ). SC: {danh sách}"}
|
|
635
|
+
Self-review: {✅ sạch | ⚠️ {n} điểm cần chú ý — liệt kê}
|
|
344
636
|
Next : /qc-review {UC-ID} ← review test case trước khi sinh script
|
|
345
637
|
```
|