@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
package/core/FRAMEWORK_VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
0.9.
|
|
1
|
+
0.9.6
|
|
@@ -7,6 +7,11 @@
|
|
|
7
7
|
> **dev self-test** để QC thấy dev đã tự chạy check của mình.
|
|
8
8
|
|
|
9
9
|
## Gate
|
|
10
|
+
|
|
11
|
+
*Checkpoint: **chặn CỨNG** — ghi đè file test đã có → XOÁ bản sửa tay của dev (mock, fixture, expectation đã chỉnh) mà chính `/dev-run-test` bảo họ làm. `--yes` KHÔNG bỏ qua được (gate Bước 3a).*
|
|
12
|
+
|
|
13
|
+
*Mức cứng chỉ áp khi file test **đã tồn tại**. Lần sinh đầu đi thẳng. Xem §Chạy lại.*
|
|
14
|
+
|
|
10
15
|
# Gate — Quy trình vào chuẩn cho mọi lệnh
|
|
11
16
|
|
|
12
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ó.
|
|
@@ -684,6 +689,63 @@ bên trong từng sub-agent.
|
|
|
684
689
|
|
|
685
690
|
---
|
|
686
691
|
|
|
692
|
+
## Output — lệnh này ghi những gì, ở đâu
|
|
693
|
+
|
|
694
|
+
| Ghi gì | Người sửa tay? |
|
|
695
|
+
|---|:---:|
|
|
696
|
+
| File **unit / integration / E2E test** theo layout của `{active_module}` | ✅ **có** — xem §Chạy lại |
|
|
697
|
+
| Sổ trace: `test_count` · `test_classes` · `dev_selftest` | ❌ lệnh ghi |
|
|
698
|
+
|
|
699
|
+
> **Vì sao mục này tồn tại** *(G84)*. Trước đó §Output chỉ khai `Trace: …tsv updated` — **không
|
|
700
|
+
> khai file test nó ghi ra**. Một lệnh không khai mình ghi gì thì không ai nghĩ tới việc **bảo vệ
|
|
701
|
+
> thứ nó ghi**. Đúng lỗi gốc của G77 ở lane QC. Cột *"người sửa tay?"* là câu hỏi mà
|
|
702
|
+
> `bin/trace-schema.json` → `artifact_writers` ép mọi lệnh trả lời.
|
|
703
|
+
|
|
704
|
+
## Chạy lại — file test đã tồn tại *(GIỮ phần đã có, sinh phần THIẾU)*
|
|
705
|
+
|
|
706
|
+
**Dev SỬA TAY chính các file này.** `/dev-run-test` nói thẳng:
|
|
707
|
+
|
|
708
|
+
> `:260` — *"Test fail → `/fix-bug {TICKET_ID}` (bug thật) hoặc **fix test** (sai expectation)"*
|
|
709
|
+
> `:137` — *"`TimeoutError` | Test gọi LLM endpoint live | **Thêm mock; kiểm tra test fixture**"*
|
|
710
|
+
|
|
711
|
+
Nên chuỗi bình thường là **sinh → chạy → đỏ → dev sửa tay → chạy lại**, và lần sinh sau **không được**
|
|
712
|
+
là lần xoá.
|
|
713
|
+
|
|
714
|
+
| Tình huống | Xử lý |
|
|
715
|
+
|---|---|
|
|
716
|
+
| File test đã có, `.feature` **không đổi** | **Không sinh lại.** Không hỏi gì — ca thường nhất |
|
|
717
|
+
| `.feature` có SC **mới** | Sinh **chỉ** test cho SC mới; giữ nguyên file/class đã có |
|
|
718
|
+
| File test có **thay đổi chưa commit** | **DỪNG** — xem dưới |
|
|
719
|
+
|
|
720
|
+
**Nhận diện "đã sửa tay" bằng `git status` / `git diff`** trên các đường dẫn ở §Output. Không cần ai
|
|
721
|
+
đánh dấu gì, và nó bắt được **mọi** lần sửa — kể cả lần người sửa quên đánh dấu.
|
|
722
|
+
|
|
723
|
+
```
|
|
724
|
+
❌ {n} file test có thay đổi chưa commit — có thể là bản sửa tay của bạn
|
|
725
|
+
(mock, fixture, expectation đã chỉnh). Sinh lại sẽ XOÁ chúng.
|
|
726
|
+
Files: {danh sách}
|
|
727
|
+
Cách đúng: commit bản sửa trước, rồi chạy lại.
|
|
728
|
+
Cố ý bỏ hết và sinh từ trắng: thêm --force
|
|
729
|
+
```
|
|
730
|
+
|
|
731
|
+
**KHÔNG đoán.** Thấy thay đổi chưa commit thì lệnh **không tự phân biệt** *"dev vừa sửa"* với *"lần
|
|
732
|
+
sinh trước chưa commit"* — hai ca đó nhìn giống hệt nhau trên `git status`. **Dừng oan một lần rẻ
|
|
733
|
+
hơn xoá nhầm một lần.**
|
|
734
|
+
|
|
735
|
+
> **Vì sao mặc định là "sinh phần thiếu" chứ không phải "đừng sinh".** `/qc-run-test` (G77) có vòng
|
|
736
|
+
> đời **chạy nhiều / sinh ít** nên mặc định của nó là *"CHẠY, đừng sinh lại"*. Lệnh này **chỉ sinh**,
|
|
737
|
+
> không chạy gì — copy nguyên mặc định đó sang là **copy nhầm ngữ cảnh**. *Cùng khuôn không có nghĩa
|
|
738
|
+
> là cùng thuốc.*
|
|
739
|
+
>
|
|
740
|
+
> **Vì sao ca "không đổi gì" phải HOÀN TOÀN im lặng.** Sinh lại test là việc làm mỗi lần spec đổi.
|
|
741
|
+
> Bản vá nào làm nó hỏi mỗi lần thì người dùng sẽ thêm `--force` vào alias — và lúc đó mất sạch lớp
|
|
742
|
+
> bảo vệ này.
|
|
743
|
+
|
|
744
|
+
Có `--force` → report **bắt buộc** khai:
|
|
745
|
+
```
|
|
746
|
+
⚠️ --force: sinh lại từ trắng — đã xoá {n} file test có thay đổi chưa commit: {danh sách}
|
|
747
|
+
```
|
|
748
|
+
|
|
687
749
|
## Output
|
|
688
750
|
|
|
689
751
|
**Đọc `.agent/steps/report-footer.md`** và áp đúng khuôn footer trong đó (Status Badge ·
|
|
@@ -653,6 +653,7 @@ Với mỗi UC, ghi vào path trên và set `# @trace.platform: {active_platform
|
|
|
653
653
|
# @trace.prd_version: {đọc từ metadata PRD "| **Version** |"}
|
|
654
654
|
# @trace.bdd_version: {cấp FILE — 1.0 nếu gen mới; tăng 0.1 khi gen lại. Khác @trace.sc_version (cấp từng SC) bên dưới}
|
|
655
655
|
# @trace.business_rules: {TICKET-ID}-UC{N}-BR{m}, {TICKET-ID}-UC{N}-BR{m+1} ← {m} lấy NGUYÊN từ PRD §3: BR đánh số LIÊN TỤC toàn PRD, KHÔNG reset theo UC
|
|
656
|
+
# @trace.api_source: existing ← CÓ ĐIỀU KIỆN: chỉ giữ dòng này khi @trace.platform=system VÀ PRD Metadata có "| **API Source** | existing |". Mọi ca khác (greenfield · web · app) → XOÁ HẲN DÒNG NÀY; đừng để trống, đừng ghi "—". Vắng là ĐÚNG (review-context Nhóm C)
|
|
656
657
|
# @trace.dataset: {domain}.testdata.yaml
|
|
657
658
|
# ============================================================
|
|
658
659
|
|
|
@@ -657,8 +657,45 @@ DTOs → Entity/Model → Repository → Service interface → Service impl →
|
|
|
657
657
|
|
|
658
658
|
Mỗi element **có action** (button, input, link, select, toggle, form-submit) PHẢI mang một **test-id ổn định** để QC định vị trực tiếp (không scan runtime):
|
|
659
659
|
|
|
660
|
-
1. **Nguồn id
|
|
661
|
-
|
|
660
|
+
1. **Nguồn id — bảng §4.5.6 là HỢP ĐỒNG, không phải gợi ý.** Đọc **§4.5.6 Test Selectors** cho platform này ở tech-doc gộp `{paths.tech_docs_dir}/{domain}/{prd-slug}/tech-docs/{TICKET-ID}-tech-design.md`, lọc theo cột "Serves SC" khớp SC của UC này, rồi lấy id **nguyên văn**. Bảng do `/map-testids` ghi ở phase Tech Design — **trước** lệnh này.
|
|
661
|
+
|
|
662
|
+
**Bảng rỗng hoặc không có row nào cho SC của UC này** → *không tự sinh id rồi đi tiếp*. Cảnh báo rồi **để người quyết**:
|
|
663
|
+
|
|
664
|
+
```
|
|
665
|
+
⚠️ §4.5.6 Test Selectors RỖNG cho {platform} của {TICKET-ID} — chưa có hợp đồng test-id.
|
|
666
|
+
|
|
667
|
+
Sinh code bây giờ nghĩa là mỗi id ở đây là id TẠM do lệnh này tự đặt:
|
|
668
|
+
· QC chưa bám vào được (họ đọc §4.5.6, không đọc code)
|
|
669
|
+
· /map-testids sau này phải đối chiếu lại, và có thể phải SỬA CODE nếu lệch
|
|
670
|
+
· lint-trace T18 sẽ báo "code có test-id mà bảng không có"
|
|
671
|
+
|
|
672
|
+
Cách đúng: dừng ở đây → /map-testids {UC-ID} → /review-tech-docs → chạy lại lệnh này.
|
|
673
|
+
|
|
674
|
+
Vẫn sinh code bây giờ với id tạm theo quy ước {uc-lower}-{screen}-{element}-{type}? (Y/N)
|
|
675
|
+
```
|
|
676
|
+
|
|
677
|
+
- **N** → dừng, không sinh gì.
|
|
678
|
+
- **Y** → sinh id theo quy ước, **và report cuối phải ghi rõ**: `⚠️ {n} test-id TẠM (chưa vào §4.5.6) — chạy /map-testids {UC-ID} để đưa vào hợp đồng`.
|
|
679
|
+
- **`--yes` (headless)** → coi như **Y**, nhưng dòng cảnh báo ở report là **bắt buộc**. Không được im lặng: `lint-trace --code` T18 là lưới bắt phía sau, và nó chỉ có nghĩa khi người ta biết có gì để tìm.
|
|
680
|
+
|
|
681
|
+
> **Vì sao hỏi chứ không tự sinh như trước.** Tự sinh rồi *"đối chiếu lúc integration"* nghe hợp lý nhưng thực tế là **code quyết định hợp đồng**: QC đọc §4.5.6 thấy rỗng nên đi dò DOM, còn FE đã gắn một bộ id không ai biết. Đến lúc đối chiếu thì cả hai bên đều đã làm xong theo hai hướng khác nhau. Hỏi ở đây là đặt quyết định đó vào tay người, **đúng lúc nó còn rẻ**.
|
|
682
|
+
2. **TÊN THUỘC TÍNH: đọc `@trace.testid_attr` từ header tech-doc gộp — KHÔNG tự suy từ module.** Đây là **nửa FE của contract FE↔QC**: `/qc-run-test` đọc **chính field này** để cấu hình locator, và `bin/trace-schema.json` khai `artifact: tech-design.md` (`written_by: map-testids`). Hai bên phải đọc **cùng một bản** — nếu FE suy từ module còn QC đọc tech-doc thì FE gắn một kiểu, QC tìm một kiểu, và **không trùng một element nào**.
|
|
683
|
+
|
|
684
|
+
| Đọc được gì | Làm gì |
|
|
685
|
+
|---|---|
|
|
686
|
+
| Header tech-doc có `@trace.testid_attr` | Dùng **nguyên văn** giá trị đó |
|
|
687
|
+
| **Không tìm thấy field** | **Cảnh báo mềm, KHÔNG im lặng hardcode** (khối dưới), rồi mới fallback theo `active_module` |
|
|
688
|
+
| Header `.feature` cũng khai và **LỆCH** với tech-doc | Ưu tiên tech-doc, nhưng **in cả hai giá trị** — không im lặng chọn một bên. `.feature` là lối cũ, chỉ còn cho stack lai |
|
|
689
|
+
|
|
690
|
+
Cảnh báo khi thiếu field (cùng khuôn `/qc-run-test` dùng, để hai nửa của contract nói cùng một giọng):
|
|
691
|
+
```
|
|
692
|
+
⚠️ Tech-doc thiếu @trace.testid_attr — fallback theo module ({attr mặc định}).
|
|
693
|
+
Nếu FE dùng thuộc tính khác thì MỌI locator của QC sẽ trượt, và test sẽ đỏ với
|
|
694
|
+
"element not found" — trông y hệt một bug sản phẩm, nên QC đi mở bug thay vì sửa selector.
|
|
695
|
+
Chạy /map-testids {UC-ID} để ghi field này.
|
|
696
|
+
```
|
|
697
|
+
|
|
698
|
+
**Fallback theo `active_module`** (chỉ khi tech-doc không có field):
|
|
662
699
|
- web (`react`/`nextjs`/`vue`/`angular`) → `data-testid="..."`
|
|
663
700
|
- React Native → `testID="..."`
|
|
664
701
|
- Flutter → `Key('...')` (+ `Semantics(identifier: '...')` khi action cần)
|
|
@@ -232,7 +232,7 @@ Kiểm tra `output_path` đã tồn tại chưa.
|
|
|
232
232
|
|
|
233
233
|
- **Chưa tồn tại → chế độ FRESH.** Tạo doc từ template, chỉ điền (các) UC trong `input_features`. (Section của các UC không thuộc batch này giữ placeholder `{…}` / được thêm ở lần chạy sau.)
|
|
234
234
|
- **Đã tồn tại → chế độ APPEND.** Doc là tăng dần — không bao giờ regenerate từ đầu (sẽ đè mất chỉnh tay và sign-off của reviewer). Đọc bảng **§10 UC Coverage** và **Changelog** hiện có → `covered_ucs`. Với mỗi UC trong `input_features`, phân loại:
|
|
235
|
-
- **UC mới** (không có trong `covered_ucs`) → **thêm** các section của nó: sequence diagram §5 mới **đúng lane platform** (5.A/5.B/5.C, đánh số sau cái cuối cùng hiện có *trong lane đó*); với §4.5 — nếu **platform** này mới với doc → nhóm `### 4.5 — {platform}` mới, ngược lại thêm sub-block `§4.5.1.x {Screen} — {UC}`
|
|
235
|
+
- **UC mới** (không có trong `covered_ucs`) → **thêm** các section của nó: sequence diagram §5 mới **đúng lane platform** (5.A/5.B/5.C, đánh số sau cái cuối cùng hiện có *trong lane đó*); với §4.5 — nếu **platform** này mới với doc → nhóm `### 4.5 — {platform}` mới, ngược lại thêm sub-block `§4.5.1.x {Screen} — {UC}` (đừng lặp nhóm). **§4.5.6: chỉ tạo KHUNG bảng rỗng nếu chưa có — KHÔNG ghi row nào**, xem §Phân vai §4.5.6; row mới ở §3/§4.3/§8/§9. Rồi cập nhật §10 (row khoá theo platform×SC) và thêm một row Changelog **theo format ở Bước 1b**.
|
|
236
236
|
- **UC đã phủ được trỏ lại** (có trong `covered_ucs`) → đây là refresh/mở rộng có chủ đích (vd tech lead giờ trỏ vào BDD `web/` của một UC mà backend đã thiết kế, hoặc BDD bump version). Xác nhận trước khi đụng nội dung có sẵn:
|
|
237
237
|
```
|
|
238
238
|
↻ {UC-ID} đã có trong {TICKET-ID}-tech-design.md.
|
|
@@ -378,7 +378,25 @@ Ghi/mở rộng `{output_path}` dùng template dưới đây, chỉ sinh **nội
|
|
|
378
378
|
- **§1/§2** (Overview/Actors, Architecture) là cấp PRD: viết ở lần chạy đầu; các lần sau chỉ mở rộng nếu batch thêm actor/integration thật sự mới.
|
|
379
379
|
- **§10 UC Coverage** — một row UC (có cột Platforms) + bảng con coverage-scenario khoá theo **(platform, SC)** — mỗi platform×SC một row, vì cùng số SC ở platform khác nhau là scenario khác nhau. Đây là mỏ neo mà chế độ APPEND đọc. Luôn cập nhật nó cho (các) UC/platform của batch.
|
|
380
380
|
|
|
381
|
-
**Chế độ APPEND (doc đã tồn tại):** **đừng** viết lại section có sẵn. Chèn diagram §5 của UC batch **vào đúng lane platform** (5.A/5.B/5.C, đánh số sau cái cuối trong lane đó, tiêu đề `platform · SC`), các row mới ở §3/§4.3/§8/§9; với §4.5 — platform mới → nhóm `### 4.5 — {platform}` mới, ngược lại thêm sub-block `§4.5.1.x {Screen} — {UC}`
|
|
381
|
+
**Chế độ APPEND (doc đã tồn tại):** **đừng** viết lại section có sẵn. Chèn diagram §5 của UC batch **vào đúng lane platform** (5.A/5.B/5.C, đánh số sau cái cuối trong lane đó, tiêu đề `platform · SC`), các row mới ở §3/§4.3/§8/§9; với §4.5 — platform mới → nhóm `### 4.5 — {platform}` mới, ngược lại thêm sub-block `§4.5.1.x {Screen} — {UC}` (không lặp nhóm). **§4.5.6: chỉ khung rỗng, KHÔNG ghi row** — xem §Phân vai §4.5.6; rồi cập nhật §10 (row khoá theo platform×SC) và thêm một row Changelog **theo format ở Bước 1b**. Bump `@trace.revision` và làm mới `@trace.ucs` / `@trace.platforms` ở header, và cập nhật entry của platform vừa đụng trong map `@trace.bdd_versions` (vd set `web=2.0`, giữ nguyên `system`).
|
|
382
|
+
|
|
383
|
+
## Phân vai §4.5.6 Test Selectors — lệnh này KHÔNG ghi row
|
|
384
|
+
|
|
385
|
+
Bảng §4.5.6 là **hợp đồng test-id FE↔QC**, và nó có **đúng một người ghi**: `/map-testids`.
|
|
386
|
+
Lệnh này chỉ:
|
|
387
|
+
|
|
388
|
+
- tạo **khung bảng rỗng** (dòng tiêu đề + dòng phân cách) trong mỗi nhóm `### 4.5 — {platform}` client;
|
|
389
|
+
- ghi `@trace.testid_attr` ở header dưới dạng **placeholder** (giá trị thật do `/map-testids` điền).
|
|
390
|
+
|
|
391
|
+
> **Vì sao tách người ghi.** Trước đây cả hai lệnh cùng ghi bảng, và luật chống giẫm chân là một
|
|
392
|
+
> câu văn xuôi. Quan trọng hơn: hợp đồng phải chốt **trước** `/generate-code`, để FE và QC cùng
|
|
393
|
+
> đọc một bản đã đóng băng rồi **chạy song song**. Nếu lệnh này dự đoán id còn `/map-testids` sửa
|
|
394
|
+
> lại sau khi code xong thì hợp đồng thành thứ **do code quyết định** — đúng cái nó sinh ra để
|
|
395
|
+
> chống.
|
|
396
|
+
>
|
|
397
|
+
> **Next của lệnh này là `/map-testids`**, không phải `/review-tech-docs`. `/review-tech-docs`
|
|
398
|
+
> sẽ **NEEDS_FIX** nếu có §4.5 client mà §4.5.6 rỗng (T6) — tech-doc có phần UI mà không khai
|
|
399
|
+
> test selector thì chưa viết xong, như có §4 API mà không khai endpoint.
|
|
382
400
|
|
|
383
401
|
<!--
|
|
384
402
|
════════════════════════════════════════════════════════════════════════════
|
|
@@ -422,6 +440,7 @@ Ghi/mở rộng `{output_path}` dùng template dưới đây, chỉ sinh **nội
|
|
|
422
440
|
@trace.service: {service — từ header BDD @trace.service}
|
|
423
441
|
@trace.module: {module liên quan — vd dotnet, angular}
|
|
424
442
|
@trace.platforms: {system | web | app | webview | … — tuỳ thư mục BDD nào tồn tại}
|
|
443
|
+
@trace.testid_attr: {TÊN THUỘC TÍNH chứa test-id của stack client — web `data-testid`|`data-test`|`data-qa` · React Native `testID` · Flutter `Key`/`Semantics(identifier:)` · native iOS `accessibilityIdentifier`. MỘT giá trị cho cả doc (khác GIÁ TRỊ test-id từng element — cái đó ở §4.5.6). Do `/map-testids` ghi. Để trống nếu doc chỉ phủ platform `system`.}
|
|
425
444
|
@trace.bdd_versions: {MAP theo từng platform — số nhiều, KHÁC @trace.bdd_version (scalar) của .feature — vd system=1.5, web=1.9, app=1.7; chỉ platform có mặt. Mỗi feature mang bdd_version riêng; đừng gộp về một số.}
|
|
426
445
|
@trace.api_source: {existing | —}
|
|
427
446
|
@trace.revision: 1
|
|
@@ -595,7 +614,7 @@ sở hữu (DB) vs lấy live (API ngoài), và thao tác ghi chính.}
|
|
|
595
614
|
trong CÙNG nhóm platform (không bao giờ tạo nhóm 4.5 thứ hai cho cùng platform).
|
|
596
615
|
• §4.5.2–§4.5.5 — tương tự theo màn hình/UC ở chỗ chúng khác nhau.
|
|
597
616
|
• §4.5.6 Test Selectors — MỘT bảng dùng chung cho cả nhóm platform; cột
|
|
598
|
-
"
|
|
617
|
+
"Serves SC" mang (UC · SC) để consumer per-UC lọc row của mình.
|
|
599
618
|
Append: platform mới → nhóm "### 4.5 — {platform}" mới; màn hình/UC mới trong
|
|
600
619
|
platform đã có → thêm sub-block + row vào §4.5.6 (đừng lặp nhóm).
|
|
601
620
|
Bỏ hẳn §4.5 với PRD backend-only. -->
|
|
@@ -651,11 +670,11 @@ sở hữu (DB) vs lấy live (API ngoài), và thao tác ghi chính.}
|
|
|
651
670
|
iOS accessibilityIdentifier. Dùng lại CÙNG giá trị id trên web/app cho cùng một
|
|
652
671
|
element logic.
|
|
653
672
|
MỘT bảng dùng chung cho cả nhóm platform (phủ mọi màn hình/UC của platform này).
|
|
654
|
-
Cột "
|
|
673
|
+
Cột "Serves SC" mang (UC · SC) để consumer per-UC (generate-code / qc) lọc row
|
|
655
674
|
của mình qua §10. Nhóm §4.5 này vốn đã theo platform, nên platform là ngầm định
|
|
656
675
|
(khối web → web · SC). -->
|
|
657
676
|
|
|
658
|
-
| Test-ID | Element | Component (§4.5.1.x) | Action |
|
|
677
|
+
| Test-ID | Element | Component (§4.5.1.x) | Action | Serves SC (UC · SC) |
|
|
659
678
|
|---------|---------|----------------------|--------|---------------------|
|
|
660
679
|
| `{uc}-{screen}-{element}-{type}` | {Nút submit} | {Component} | {submit} | {UC1 · SC1, UC1 · SC3} |
|
|
661
680
|
|
|
@@ -8,9 +8,43 @@
|
|
|
8
8
|
> forwarding vào figma-components catalog, patch các usage site, và ghi map §4.5.6 — để QC
|
|
9
9
|
> định vị element bằng id thay vì scan lúc runtime.
|
|
10
10
|
|
|
11
|
-
Usage: `/map-testids {UC-ID}`
|
|
11
|
+
Usage: `/map-testids {UC-ID}` · `/map-testids {UC-ID} --from-code`
|
|
12
|
+
|
|
13
|
+
## Hai chế độ — chọn theo việc code đã có hay chưa
|
|
14
|
+
|
|
15
|
+
| Chế độ | Khi nào | Nguồn element | Đụng code? | Ai chạy |
|
|
16
|
+
|---|---|---|---|---|
|
|
17
|
+
| **mặc định** (không cờ) | Feature mới — **chạy TRƯỚC `/generate-code`** | design-spec + step `When` của `.feature` | **Không** | Người viết tech-doc |
|
|
18
|
+
| `--from-code` | Brownfield — màn đã có code từ trước framework | **đọc code thật** + design-spec + BDD | Có (patch attribute) | Dev · chạy **một lần** mỗi UC cũ |
|
|
19
|
+
|
|
20
|
+
Chế độ mặc định **bỏ qua Step 3 và Step 4** (patch catalog / patch usage site): chưa có code để
|
|
21
|
+
patch, mọi element đều là `new`. Chỉ chạy Step 1 → 2 → 5.
|
|
22
|
+
|
|
23
|
+
> **Vì sao lệnh này chạy TRƯỚC `/generate-code`.** Nguyên liệu để **đặt tên** test-id có từ
|
|
24
|
+
> trước code — Step 1 lấy element từ design-spec + step `When`, cả hai đều thuộc phase Tech
|
|
25
|
+
> Design. Chốt hợp đồng ở đây rồi thì:
|
|
26
|
+
>
|
|
27
|
+
> ```
|
|
28
|
+
> /review-tech-docs (APPROVED)
|
|
29
|
+
> ├──→ /generate-code FE gắn attribute theo hợp đồng
|
|
30
|
+
> └──→ /qc-analyze → /qc-plan → /qc-design-test QC viết test case theo CÙNG hợp đồng
|
|
31
|
+
> ```
|
|
32
|
+
>
|
|
33
|
+
> **Cửa vào làn QC là `/qc-analyze`, KHÔNG phải `/qc-design-test`.** Trạm 3 tiêu thụ output của
|
|
34
|
+
> trạm 1–2 (`REQUIREMENT_ANALYSIS.md` · `DOC_GAP.md` · `TEST_PLAN.md`); trỏ thẳng vào nó là chỉ
|
|
35
|
+
> người ta nhảy vào giữa dây chuyền. Cả ba trạm đầu **không cần code**, nên nhánh QC vẫn song song
|
|
36
|
+
> trọn vẹn với `/generate-code` — chỉ trạm 5 `/qc-run-test` mới cần code chạy được.
|
|
37
|
+
>
|
|
38
|
+
> Hai nhánh **không chờ nhau** vì cùng đọc một bản đã đóng băng, không đọc output của nhau.
|
|
39
|
+
> Chạy sau code thì QC phải xếp hàng, và `/generate-code` không có gì để đọc nên sẽ tự sinh id
|
|
40
|
+
> — hợp đồng thành thứ do code quyết định.
|
|
12
41
|
|
|
13
42
|
## Gate
|
|
43
|
+
|
|
44
|
+
*Checkpoint: **chặn CỨNG** — ghi đè §4.5.6 đã có → ĐỔI id hợp đồng mà SA viết tay, và kéo theo Step 5b hạ `qc_status` + bump `tech_doc_revision` cho một hợp đồng **chưa hỏng**. `--yes` KHÔNG bỏ qua được (gate Bước 3a).*
|
|
45
|
+
|
|
46
|
+
*Mức cứng chỉ áp khi §4.5.6 **đã có row**. Tech-doc chưa có bảng — brownfield thật, ca lệnh này **sinh ra để phục vụ** — đi thẳng, không CHECKPOINT cứng. Xem Step 2 §Bảng đã có id.*
|
|
47
|
+
|
|
14
48
|
# Gate — Quy trình vào chuẩn cho mọi lệnh
|
|
15
49
|
|
|
16
50
|
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ó.
|
|
@@ -188,8 +222,15 @@ Phân giải attribute test-id từ `@trace.testid_attr` (hoặc theo module): w
|
|
|
188
222
|
|
|
189
223
|
Từ các step `When` trong `.feature` FE của UC + các màn Design Spec, liệt kê mọi element **có action** mà scenario chạm tới (button, input, link, select, toggle, form-submit). Bỏ qua text/label tĩnh. Với mỗi cái, phân giải component render và phân loại:
|
|
190
224
|
- **reused** — khớp một row trong figma-components catalog (component design-system dùng chung);
|
|
191
|
-
- **existing** — component riêng của feature đã có trong codebase (brownfield);
|
|
192
|
-
- **new** — chưa code (để `/generate-code` lo; chỉ ghi lại id dự kiến).
|
|
225
|
+
- **existing** — component riêng của feature đã có trong codebase (brownfield); *chỉ gặp ở `--from-code`*;
|
|
226
|
+
- **new** — chưa code (để `/generate-code` lo; chỉ ghi lại id dự kiến). *Chế độ mặc định: **mọi** element đều là nhóm này.*
|
|
227
|
+
|
|
228
|
+
Phân loại này là **nội bộ lúc chạy** — dùng để rẽ nhánh Step 2–4. **Không ghi vào bảng §4.5.6**
|
|
229
|
+
(xem Step 5): nó đổi theo thời gian, một element `new` thành `existing` ngay khi dev viết code.
|
|
230
|
+
|
|
231
|
+
**Cột `Component` của bảng** lấy từ **§4.5.1 Cây Component trong chính tech-doc này** (do
|
|
232
|
+
`/generate-tech-docs` vẽ từ design-spec) — trỏ `§4.5.1.x`. §4.5.1 chưa có (ca `--from-code` ghi
|
|
233
|
+
file tối thiểu) thì ghi tên component.
|
|
193
234
|
|
|
194
235
|
## Step 2 — Phân giải test-id ổn định cho mỗi element
|
|
195
236
|
|
|
@@ -197,7 +238,48 @@ Từ các step `When` trong `.feature` FE của UC + các màn Design Spec, li
|
|
|
197
238
|
- **Reused:** id được áp ở **usage site** (không bake vào component dùng chung) → gán theo cùng quy ước.
|
|
198
239
|
- **Cross-platform:** nếu §4.5.6 của platform **kia** (block `web`/`app` trong cùng tech-doc gộp) đã có id cho cùng element logic, **dùng lại id value đó** (chỉ attribute khác theo platform) để web và app nhất quán và logic QC tái dùng được.
|
|
199
240
|
|
|
200
|
-
|
|
241
|
+
### Bảng §4.5.6 ĐÃ CÓ id cho element này → **DÙNG LẠI AS-IS** *(G83)*
|
|
242
|
+
|
|
243
|
+
Đối xứng với luật *reverse-document* cho code ở gạch đầu tiên. Chỉ gán id mới cho element **chưa có
|
|
244
|
+
row**. Quy ước `{uc-lower}-{screen}-{element}-{type}` là **mặc định cho id MỚI** — **không** phải
|
|
245
|
+
chuẩn để chuẩn-hoá lại id đã có.
|
|
246
|
+
|
|
247
|
+
| Tình huống | Xử lý |
|
|
248
|
+
|---|---|
|
|
249
|
+
| Element **đã có row** trong §4.5.6 | **Giữ nguyên id**. Cập nhật cột `Element`/`Component`/`Action` nếu thật sự đổi; **không đụng cột Test-ID** |
|
|
250
|
+
| Element **chưa có row** | Gán theo quy ước, thêm row mới |
|
|
251
|
+
| Row trong bảng mà element **không còn** trong design-spec/BDD | **Không xoá** — nêu ở report để người quyết *(có thể đang phục vụ UC khác)* |
|
|
252
|
+
|
|
253
|
+
> **Vì sao as-is chứ không chuẩn hoá.** Bảng là **HỢP ĐỒNG**, không phải output của lệnh này. Chuẩn
|
|
254
|
+
> hoá một hợp đồng mà **cả FE lẫn QC đang bám vào**, chỉ vì tên không theo ý lệnh, là đổi hợp đồng
|
|
255
|
+
> **mà không ai yêu cầu** — rồi Step 5b trung thành hạ `qc_status` và bump revision cho một thứ chưa
|
|
256
|
+
> hỏng gì.
|
|
257
|
+
>
|
|
258
|
+
> **Đây là lỗ hổng lâu nhất của lệnh này** *(G83)*. Luật *"đã có test-id → dùng lại as-is"* vốn đã có
|
|
259
|
+
> ở gạch đầu — nhưng **chỉ cho CODE**. Vế cho BẢNG bị thiếu, trong khi bảng mới là hợp đồng còn code
|
|
260
|
+
> là bên phải tuân theo nó. Đo trên dự án thật: **28/28 tech-doc** có §4.5.6 **viết tay**, quy ước
|
|
261
|
+
> riêng (`uc{n}-z2-region` · `uc1-z2-rank-avatar / uc1-z2-rank-name`) mà lệnh này không tái tạo được.
|
|
262
|
+
|
|
263
|
+
### `--force` — đổi tên hàng loạt *(ca hợp lệ, nhưng phải nói ra)*
|
|
264
|
+
|
|
265
|
+
Đổi convention toàn dự án là việc thật. Không có cờ → **DỪNG**:
|
|
266
|
+
|
|
267
|
+
```
|
|
268
|
+
❌ §4.5.6 của {TICKET-ID} ({platform}) đã có {n} id — giữ nguyên theo mặc định.
|
|
269
|
+
Muốn đặt lại tên toàn bộ theo quy ước framework: thêm --force
|
|
270
|
+
⚠️ --force sẽ đổi {n} id mà FE đang gắn và QC đang bám:
|
|
271
|
+
· code FE trượt locator cho tới khi gắn lại (lint T17/T18 sẽ kêu)
|
|
272
|
+
· .Test.md bám id cũ (lint T19 sẽ kêu)
|
|
273
|
+
· qc_status của mọi SC liên quan → not_run (Step 5b)
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
Có `--force` → report **bắt buộc** khai:
|
|
277
|
+
```
|
|
278
|
+
⚠️ --force: đã đổi {n} id hợp đồng — {danh sách id cũ → mới}
|
|
279
|
+
Chạy lại: /generate-code (FE gắn id mới) · /qc-design-test {UC-ID} (TC bám id mới)
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
## Step 3 — Đảm bảo component tái dùng forward được test-id (catalog) *(chỉ `--from-code`)*
|
|
201
283
|
|
|
202
284
|
Với mỗi component **reused** có action, tra section **`## Test-ID Forwarding`** của catalog (`{paths.domain_knowledge_dir}/figma-components/{active_module}.md`):
|
|
203
285
|
- **Đã ghi prop forwarding** → dùng nó ở usage site (Step 4).
|
|
@@ -207,17 +289,92 @@ Với mỗi component **reused** có action, tra section **`## Test-ID Forwardin
|
|
|
207
289
|
|
|
208
290
|
In mọi row catalog được thêm và mọi component dùng chung được patch (chúng đụng code dùng chung — nêu ra để review).
|
|
209
291
|
|
|
210
|
-
## Step 4 — Patch usage site (chỉ EXTEND)
|
|
292
|
+
## Step 4 — Patch usage site (chỉ EXTEND) *(chỉ `--from-code`)*
|
|
211
293
|
|
|
212
294
|
Với mỗi element có action trong các màn **existing/reused** của UC này, thêm test-id ở usage site — attribute thô cho element thường, hoặc prop forwarding cho component tái dùng — với id từ Step 2. **EXTEND mode:** chỉ đụng attribute/prop; không refactor gì khác. Bỏ qua element đã mang đúng id (idempotent).
|
|
213
295
|
|
|
214
296
|
## Step 5 — Ghi/làm mới map §4.5.6 Test Selectors
|
|
215
297
|
|
|
216
298
|
Tạo hoặc cập nhật §4.5.6 (block platform tương ứng) trong tech-doc gộp `{paths.tech_docs_dir}/{domain}/{prd-slug}/tech-docs/{TICKET-ID}-tech-design.md`:
|
|
217
|
-
- Nếu tech-doc tồn tại →
|
|
299
|
+
- Nếu tech-doc tồn tại → **hai việc, không bỏ việc nào**:
|
|
300
|
+
- **(a) Header.** Đảm bảo khối `@trace` có `@trace.testid_attr` mang đúng giá trị đã phân giải ở Step 0. Thiếu hẳn, hoặc còn placeholder `{…}` → điền. **Đã có giá trị thật mà LỆCH với giá trị vừa phân giải → DỪNG, in cả hai giá trị và hỏi người dùng chọn**; không tự ghi đè.
|
|
301
|
+
- **(b) Bảng.** Cập nhật bảng §4.5.6 của platform này (thêm block §4.5 cho platform nếu chưa có).
|
|
218
302
|
- Nếu **chưa** tồn tại (pure brownfield) → ghi một file tối thiểu: header `@trace` (gồm `@trace.testid_attr`) + §4.5.6. `/generate-tech-docs` điền các section còn lại sau; nó không được ghi đè các id §4.5.6 mà lệnh này đã ghi.
|
|
219
303
|
|
|
220
|
-
|
|
304
|
+
> **Vì sao (a) lệch thì DỪNG chứ không ghi đè.** `@trace.testid_attr` là *tên thuộc tính* mà **mọi** locator QC của PRD này bám vào (`/qc-run-test` đọc nó để cấu hình `get_by_test_id`). Ghi đè sai một lần là làm **trượt toàn bộ** script của PRD — và test sẽ đỏ với `element not found`, trông y hệt một bug sản phẩm, nên QC đi mở bug thay vì sửa selector. Lệch nghĩa là một trong hai đang sai: FE vừa đổi convention, hoặc `active_module` khai sai. Cả hai đều cần người nhìn, không đoán được từ đây.
|
|
305
|
+
|
|
306
|
+
Mỗi row — **5 cột, đúng thứ tự của template** (`templates/tech-design.template.md` §4.5.6):
|
|
307
|
+
|
|
308
|
+
`Test-ID | Element | Component | Action | Serves SC (UC · SC)`
|
|
309
|
+
|
|
310
|
+
- **Component** — trỏ `§4.5.1.x` nếu §4.5.1 đã vẽ; chưa có (ca brownfield ghi file tối thiểu) thì ghi tên component.
|
|
311
|
+
- **Serves SC** — danh sách `(UC · SC)` mà id này phục vụ. Một id phục vụ nhiều UC là **bình thường**: tiền tố UC trong tên id chỉ nói UC nào giới thiệu element đó đầu tiên.
|
|
312
|
+
|
|
313
|
+
> **KHÔNG ghi phân loại `reused`/`existing`/`new` vào bảng.** Nó là phân loại **lúc chạy** của Step 1 (dùng để rẽ nhánh Step 2–4), và nó **đổi theo thời gian** — một element `new` thành `existing` ngay khi dev viết code. Nhét dữ liệu biến thiên vào bảng hợp đồng là làm bảng sai dần mà không ai cập nhật.
|
|
314
|
+
>
|
|
315
|
+
> **Thứ tự cột là load-bearing:** `lint-trace` **T15** đọc cột "Serves SC" theo **vị trí** (ô nội dung cuối cùng) để đối chiếu với `.feature`. Viết sai thứ tự là T15 đọc nhầm ô.
|
|
316
|
+
|
|
317
|
+
## Step 5b — Làm mất hiệu lực `qc_status` của SC bị ảnh hưởng *(chỉ khi ĐỔI id đã có)*
|
|
318
|
+
|
|
319
|
+
Chạy **chỉ khi** Step 5 làm đổi giá trị một test-id **đã tồn tại** trong bảng (thêm row mới
|
|
320
|
+
không kích hoạt bước này — chưa có script nào bám id mới).
|
|
321
|
+
|
|
322
|
+
Đổi một id nghĩa là mọi script QC bám id cũ **hết đúng**: nó đang định vị một element không còn
|
|
323
|
+
mang id đó. Giữ `qc_status = pass` ở đó là **báo cáo sai** — `rules/workflow.md` §*"Làm mất hiệu
|
|
324
|
+
lực ≠ ghi đè"*: *"lệnh nào làm giá trị đó HẾT ĐÚNG thì BẮT BUỘC hạ nó về giá trị 'chưa biết'"*.
|
|
325
|
+
|
|
326
|
+
```
|
|
327
|
+
với mỗi id ĐỔI:
|
|
328
|
+
đọc cột "Serves SC" của row đó → danh sách {UC-ID}-SC{N}
|
|
329
|
+
mở sổ {paths.trace_dir}/{domain}/{prd-slug}/{UC-ID}-{platform}.tsv
|
|
330
|
+
với mỗi SC trong danh sách:
|
|
331
|
+
qc_status → not_run (chỉ hạ từ `pass`/`fail`; đang `not_run`/`skip` thì để yên)
|
|
332
|
+
qc_run_at → —
|
|
333
|
+
tech_doc_revision → @trace.revision MỚI của tech-doc ← bump, xem dưới
|
|
334
|
+
```
|
|
335
|
+
|
|
336
|
+
### Bump `tech_doc_revision` — vì sao lệnh này cũng là một bumper *(G64)*
|
|
337
|
+
|
|
338
|
+
Tăng `@trace.revision` ở header tech-doc, rồi ghi số mới vào cột `tech_doc_revision` của **mọi row
|
|
339
|
+
trong các sổ vừa chạm**.
|
|
340
|
+
|
|
341
|
+
§4.5.6 là hợp đồng mà `/qc-design-test` **chép cứng giá trị id vào `.Test.md`** — một artifact **bền,
|
|
342
|
+
nằm lại**. Cơ chế phát hiện lỗi thời của tầng artifact QC (`steps/qc-stamp.md`) hoạt động theo **nhãn**:
|
|
343
|
+
`.Test.md` đóng dấu `tech_doc_revision`, trạm 4–5 so với hiện tại. **Sửa §4.5.6 mà không bump nhãn thì
|
|
344
|
+
cơ chế đó không nổ** — đúng ca quan trọng nhất.
|
|
345
|
+
|
|
346
|
+
> **Vì sao không dựa vào `Next` → `/review-tech-docs`.** Lệnh đó **có** bump (`:396` — set
|
|
347
|
+
> `tech_doc_revision` cho mọi row). Nhưng đường ấy chỉ đúng **khi người dùng đi theo `Next`**, mà
|
|
348
|
+
> Step 5b này tồn tại chính vì ca *"sửa nhanh một id rồi đi tiếp"*. Dựa vào `Next` là dựa vào **kỷ
|
|
349
|
+
> luật**, không phải vào máy — và `rules/workflow.md` gọi chỗ này là **điểm mù tuyệt đối**: *"mọi
|
|
350
|
+
> drift detector so **nhãn version**, không so **nội dung**"*. Không bump là tự tay đi vòng qua nhãn.
|
|
351
|
+
>
|
|
352
|
+
> **Thêm row MỚI thì KHÔNG bump** — cùng điều kiện với việc hạ `qc_status`: chưa `.Test.md` nào bám
|
|
353
|
+
> id mới, không gì hết đúng.
|
|
354
|
+
|
|
355
|
+
**KHÔNG đụng `qc_owner` và `qc_blocked_by`.** `rules/workflow.md` miễn trừ tường minh hai cột
|
|
356
|
+
này: chúng là **con trỏ tới bug**, và đổi một test-id không làm con bug biến mất. Xoá đi là mất
|
|
357
|
+
đường về bug đang mở.
|
|
358
|
+
|
|
359
|
+
**Không có sổ trace cho SC đó** (chưa chạy `/generate-bdd`, hoặc SC mới) → bỏ qua, không tạo sổ.
|
|
360
|
+
|
|
361
|
+
In ra ở report:
|
|
362
|
+
```
|
|
363
|
+
⚠️ {n} scenario có TC/script QC bám id CŨ — qc_status hạ về not_run: {danh sách SC}
|
|
364
|
+
tech_doc_revision bump → {rev mới} (để .Test.md lỗi thời bị phát hiện ở trạm 4-5)
|
|
365
|
+
Chạy /qc-design-test lại cho các UC đó.
|
|
366
|
+
```
|
|
367
|
+
|
|
368
|
+
> **Chỉ `/qc-design-test`, KHÔNG phải "hoặc `/qc-run-test`"** *(G64 — lời nhắc cũ chỉ sai đường)*.
|
|
369
|
+
> `/qc-run-test` dựng locator từ §4.5.6 **tươi** nên phần locator nó tự cứu — nhưng nó **không sửa**
|
|
370
|
+
> id cũ đã nằm trong `.Test.md`. Ai chọn vế đó sẽ thấy test xanh trở lại và tưởng xong, trong khi tài
|
|
371
|
+
> liệu test vẫn mô tả một element không còn mang id đó.
|
|
372
|
+
|
|
373
|
+
> **Vì sao hạ chứ không giữ.** `rules/workflow.md`: *"`pass` **không** mang nghĩa 'test đã chạy
|
|
374
|
+
> xanh' — nó mang nghĩa 'scenario này đã được nghiệm thu theo spec **hiện tại**'."* Một script
|
|
375
|
+
> định vị bằng id không còn tồn tại thì không nghiệm thu được gì cả. Và QC biết phải chạy lại
|
|
376
|
+
> bằng đúng cách họ vẫn biết với mọi thay đổi spec khác: dashboard hiện SC đó `not_run` thay vì
|
|
377
|
+
> `pass` — không phải học cơ chế mới nào.
|
|
221
378
|
|
|
222
379
|
## Step 6 — Handoff
|
|
223
380
|
|