@educa-corp/sdd-framework 0.9.3 → 0.9.5
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 -0
- package/bin/lint-trace.js +230 -2
- package/bin/qc-base-map.json +119 -49
- package/bin/self-check.js +54 -0
- package/bin/trace-schema.json +58 -4
- package/core/FRAMEWORK_VERSION +1 -1
- package/core/commands/generate-bdd.md +1 -0
- package/core/commands/generate-code.md +39 -2
- package/core/commands/generate-tech-docs.md +21 -2
- package/core/commands/map-testids.md +88 -8
- package/core/commands/qc-analyze.md +429 -472
- package/core/commands/qc-design-test.md +251 -207
- package/core/commands/qc-plan.md +97 -197
- package/core/commands/qc-report.md +76 -60
- package/core/commands/qc-review.md +135 -185
- package/core/commands/qc-run-test.md +235 -274
- package/core/commands/review-tech-docs.md +20 -0
- package/core/commands/setup-ai-first.md +5 -5
- package/core/commands/update-framework.md +1 -1
- package/core/commands/validate-traces.md +1 -1
- package/core/modules/qc-playwright/stack-profile.yaml +1 -1
- package/core/rules/data-protection.md +52 -0
- package/core/rules/workflow.md +1 -1
- package/core/skills/qc/_shared/self-review-principles.md +112 -0
- package/core/skills/qc/qa-analyst/DOC_GAP.template.md +1 -1
- package/core/skills/qc/qa-analyst/spec-breakdown.md +2 -2
- package/core/skills/qc/qa-designer/api/auth-chain.md +155 -0
- package/core/skills/qc/qa-designer/api/auth-sequence.md +75 -0
- package/core/skills/qc/qa-designer/api/common-headers.md +61 -0
- package/core/skills/qc/qa-designer/api/crud-sequence.md +122 -0
- package/core/skills/qc/qa-designer/api/endpoint.md +231 -0
- package/core/skills/qc/qa-designer/api/http-status-codes.md +102 -0
- package/core/skills/qc/qa-designer/e2e/journey.md +13 -8
- package/core/skills/qc/qa-designer/exploratory/charter.md +2 -0
- package/core/skills/qc/qa-designer/exploratory/explore-to-functional.md +7 -4
- package/core/skills/qc/qa-designer/functional/api.md +87 -18
- package/core/skills/qc/qa-designer/functional/gui-feature.md +12 -9
- package/core/skills/qc/qa-designer/functional/gui-screen.md +12 -10
- package/core/skills/qc/qa-designer/integration/api.md +12 -5
- package/core/skills/qc/qa-designer/integration/db.md +12 -6
- package/core/skills/qc/qa-designer/integration/gui.md +12 -5
- package/core/skills/qc/qa-designer/integration/kafka.md +12 -5
- package/core/skills/qc/qa-designer/non-functional.md +12 -5
- package/core/skills/qc/qa-designer/shared/action-keywords-glossary.md +91 -0
- package/core/skills/qc/qa-designer/shared/duplicate-check-procedure.md +105 -0
- package/core/skills/qc/qa-designer/shared/implicit-scenarios.md +22 -0
- package/core/skills/qc/qa-designer/shared/precision-rules.md +198 -0
- package/core/skills/qc/qa-designer/shared/read-doc-gap-inputs.md +25 -0
- package/core/skills/qc/qa-designer/shared/skill-decision-tree.md +93 -0
- package/core/skills/qc/qa-designer/shared/tc-metadata-format.md +243 -0
- package/core/skills/qc/qa-planner/risk-model.md +1 -1
- package/core/skills/qc/qa-reviewer/script/e2e.md +9 -1
- package/core/skills/qc/qa-reviewer/script/exploratory.md +9 -1
- package/core/skills/qc/qa-reviewer/script/functional.md +9 -1
- package/core/skills/qc/qa-reviewer/script/integration.md +9 -1
- package/core/skills/qc/qa-reviewer/script/non-functional.md +9 -1
- package/core/skills/qc/qa-reviewer/shared/read-doc-gap-inputs.md +26 -0
- package/core/skills/qc/qa-reviewer/shared/review-check-groups.md +207 -0
- package/core/skills/qc/qa-reviewer/shared/review-file-template.md +228 -0
- package/core/skills/qc/qa-reviewer/test-case/e2e.md +71 -13
- package/core/skills/qc/qa-reviewer/test-case/exploratory.md +53 -4
- package/core/skills/qc/qa-reviewer/test-case/functional.md +63 -15
- package/core/skills/qc/qa-reviewer/test-case/integration.md +64 -12
- package/core/skills/qc/qa-reviewer/test-case/non-functional.md +72 -13
- package/core/skills/qc/qa-runner/e2e.md +3 -3
- 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/report-footer.md +3 -3
- package/core/templates/feature.template +1 -0
- package/core/templates/tech-design.template.md +1 -0
- package/docs/02-concepts/pipeline-steps/09-validate-traces.md +1 -1
- package/docs/04-reference/commands.md +1 -1
- package/docs/04-reference/trace-schema.md +39 -1
- package/docs/explain/00-setup-ai-first.md +1 -1
- package/docs/explain/11-map-testids.md +70 -69
- package/docs/plans/qc-implementation-log.md +145 -3
- 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/bin/trace-schema.json
CHANGED
|
@@ -782,11 +782,12 @@
|
|
|
782
782
|
{
|
|
783
783
|
"n": 10,
|
|
784
784
|
"name": "qc_status",
|
|
785
|
-
"$comment": "Chủ (ghi pass/fail/skip): qc-run-test — DUY NHẤT. Invalidator (chỉ hạ về not_run khi spec/code vừa đổi): generate-bdd · generate-code. Xem dev_selftest + rules/workflow.md 'Làm mất hiệu lực ≠ ghi đè'.",
|
|
785
|
+
"$comment": "Chủ (ghi pass/fail/skip): qc-run-test — DUY NHẤT. Invalidator (chỉ hạ về not_run khi spec/code/HỢP ĐỒNG TEST-ID vừa đổi): generate-bdd · generate-code · map-testids. Xem dev_selftest + rules/workflow.md 'Làm mất hiệu lực ≠ ghi đè'. map-testids vào danh sách này vì đổi một test-id trong §4.5.6 làm script QC bám id cũ HẾT ĐÚNG: nó định vị một element không còn mang id đó, nên `pass` cũ không còn nghĩa 'scenario đã được nghiệm thu theo spec hiện tại'. Cột 'Phục vụ SC' của row chính là chỉ mục ngược để biết SC nào bị ảnh hưởng.",
|
|
786
786
|
"written_by": [
|
|
787
787
|
"qc-run-test",
|
|
788
788
|
"generate-bdd",
|
|
789
|
-
"generate-code"
|
|
789
|
+
"generate-code",
|
|
790
|
+
"map-testids"
|
|
790
791
|
],
|
|
791
792
|
"read_by": [
|
|
792
793
|
"validate-traces",
|
|
@@ -799,11 +800,12 @@
|
|
|
799
800
|
{
|
|
800
801
|
"n": 11,
|
|
801
802
|
"name": "qc_run_at",
|
|
802
|
-
"$comment": "Chủ: qc-run-test. Invalidator (hạ về —): generate-bdd · generate-code. Xem qc_status.",
|
|
803
|
+
"$comment": "Chủ: qc-run-test. Invalidator (hạ về —): generate-bdd · generate-code · map-testids. Xem qc_status.",
|
|
803
804
|
"written_by": [
|
|
804
805
|
"qc-run-test",
|
|
805
806
|
"generate-bdd",
|
|
806
|
-
"generate-code"
|
|
807
|
+
"generate-code",
|
|
808
|
+
"map-testids"
|
|
807
809
|
],
|
|
808
810
|
"read_by": [
|
|
809
811
|
"validate-traces",
|
|
@@ -1775,6 +1777,58 @@
|
|
|
1775
1777
|
}
|
|
1776
1778
|
]
|
|
1777
1779
|
},
|
|
1780
|
+
"testid_contract": {
|
|
1781
|
+
"$comment": [
|
|
1782
|
+
"HỢP ĐỒNG TEST-ID FE↔QC — phần được MÁY canh.",
|
|
1783
|
+
"",
|
|
1784
|
+
"Contract gồm hai nửa, ở hai chỗ khác nhau trong CÙNG một tech-doc:",
|
|
1785
|
+
" @trace.testid_attr (header, scope file) → TÊN THUỘC TÍNH, MỘT giá trị cho cả doc",
|
|
1786
|
+
" bảng §4.5.6 (thân, theo nền) → GIÁ TRỊ test-id từng element, N dòng",
|
|
1787
|
+
"Consumer per-UC lọc row của mình qua cột 'Phục vụ SC (UC · SC)'.",
|
|
1788
|
+
"",
|
|
1789
|
+
"VÌ SAO CẦN CANH: trước khối này, bảng §4.5.6 được 3 lệnh ĐỌC (generate-code, qc-run-test,",
|
|
1790
|
+
"qc-design-test) và 2 lệnh GHI (generate-tech-docs, map-testids) — mà 0 nơi kiểm. Luật chống",
|
|
1791
|
+
"giẫm chân giữa hai người ghi là một CÂU VĂN XUÔI ở map-testids Step 5. Đây đúng hình dạng",
|
|
1792
|
+
"đã gặp bốn lần trong loạt GAP: luật ĐÚNG, viết RÕ, và KHÔNG AI CANH (G1 · G28 · G41 · G55).",
|
|
1793
|
+
"",
|
|
1794
|
+
"PHẠM VI NEO VÀO SỰ TỒN TẠI CỦA HỢP ĐỒNG — điều khoản quan trọng nhất của khối này:",
|
|
1795
|
+
"doc không có block §4.5 client thì KHÔNG kiểm gì. Dự án backend-only, hay dự án chưa từng",
|
|
1796
|
+
"chạy /map-testids, phải im lặng hoàn toàn. Hai rule nói 'chỗ nào đã hứa thì phải giữ',",
|
|
1797
|
+
"KHÔNG nói 'mọi chỗ đều phải có hợp đồng'. Thiếu điều khoản này thì mọi dự án đang chạy đỏ",
|
|
1798
|
+
"ngay ngày nâng version, và việc đầu tiên người ta làm là thêm --warn-only vào CI.",
|
|
1799
|
+
"",
|
|
1800
|
+
"KHÔNG vào gate.blocking: đây là nợ cần thấy, không phải 'đang có cái sai' chặn PR.",
|
|
1801
|
+
"Cùng nhóm với TECHDOC_DRIFT / BDD_DRIFT — 13/17 cờ audit hiện tại cũng không chặn."
|
|
1802
|
+
],
|
|
1803
|
+
"artifact": "tech-design.md",
|
|
1804
|
+
"header_field": "@trace.testid_attr",
|
|
1805
|
+
"table_section": "4.5.6",
|
|
1806
|
+
"serves_column": "Phục vụ SC",
|
|
1807
|
+
"lint_rules": [
|
|
1808
|
+
{
|
|
1809
|
+
"rule": "T15",
|
|
1810
|
+
"level": "error",
|
|
1811
|
+
"why": "Row §4.5.6 trỏ tới SC không tồn tại trong .feature. Consumer per-UC LỌC theo cột 'Phục vụ SC' — trỏ vào SC đã bị gộp/xoá thì không khớp row nào, QC tưởng element không có test-id rồi đi dò DOM. Đây là phép so khớp chuỗi, không có chỗ cho suy luận, nên ERROR."
|
|
1812
|
+
},
|
|
1813
|
+
{
|
|
1814
|
+
"rule": "T16",
|
|
1815
|
+
"level": "error+warn",
|
|
1816
|
+
"why": "Có §4.5 client mà header thiếu @trace.testid_attr → ERROR: QC sẽ đoán tên thuộc tính theo nền, và dự án dùng data-test/data-qa TRƯỢT 100% locator trong im lặng (test đỏ 'element not found' trông y hệt bug sản phẩm). Field còn ở dạng placeholder → WARN, không ERROR: tech-doc vừa sinh ra chưa chạy /map-testids là trạng thái HỢP LỆ trong quy trình, báo đỏ ở đó là bắt oan."
|
|
1817
|
+
},
|
|
1818
|
+
{
|
|
1819
|
+
"rule": "T17",
|
|
1820
|
+
"level": "warn",
|
|
1821
|
+
"needs": "--code",
|
|
1822
|
+
"why": "Id đã khai ở §4.5.6 mà KHÔNG có trong code: FE chưa gắn, gắn sai giá trị, hoặc element đã đổi lúc implement. QC sẽ trượt locator đúng ở những id đó. WARN chứ không ERROR vì id đoán từ thiết kế không sống sót 100% — dev có thể gộp/tách element lúc implement, và đó là nợ cần thấy chứ không phải cái sai chặn người."
|
|
1823
|
+
},
|
|
1824
|
+
{
|
|
1825
|
+
"rule": "T18",
|
|
1826
|
+
"level": "warn",
|
|
1827
|
+
"needs": "--code",
|
|
1828
|
+
"why": "Id nằm trong code mà không có trong §4.5.6 nào: ai đó gắn ngoài hợp đồng — thường là /generate-code chạy khi bảng rỗng (người dùng chọn 'vẫn sinh với id TẠM'), hoặc sửa tay. Đây là lưới bắt phía sau cho quyết định đó: hợp đồng không còn đủ, và QC không biết những id này tồn tại. Chính vì có T18 mà /generate-code được phép hỏi rồi đi tiếp thay vì chặn cứng."
|
|
1829
|
+
}
|
|
1830
|
+
]
|
|
1831
|
+
},
|
|
1778
1832
|
"strict_use_check": {
|
|
1779
1833
|
"$comment": [
|
|
1780
1834
|
"R3 CANH 'CÓ NHẮC TÊN', KHÔNG CANH 'CÓ DÙNG'. Khối này siết đúng những field mà trả lời",
|
package/core/FRAMEWORK_VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
0.9.
|
|
1
|
+
0.9.5
|
|
@@ -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 "Phục vụ 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
|
|
@@ -8,7 +8,31 @@
|
|
|
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-design-test QC viết test case + script theo CÙNG hợp đồng
|
|
31
|
+
> ```
|
|
32
|
+
>
|
|
33
|
+
> 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.
|
|
34
|
+
> 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
|
|
35
|
+
> — hợp đồng thành thứ do code quyết định.
|
|
12
36
|
|
|
13
37
|
## Gate
|
|
14
38
|
# Gate — Quy trình vào chuẩn cho mọi lệnh
|
|
@@ -164,7 +188,7 @@ Mỗi dòng ⚠️/🔴 phải ứng với một trạng thái **context-loader
|
|
|
164
188
|
🔴/⚠️ (không chặn ≠ không báo — người đọc log sau này vẫn cần thấy).
|
|
165
189
|
|
|
166
190
|
|
|
167
|
-
*Lưu ý: Với lệnh này, target ở Bước 1 là một UC-ID. Đọc `.feature` FE của UC (web/app), các màn Design Spec của nó, tech-doc gộp `{paths.tech_docs_dir}/{domain}/{prd-slug}/tech-docs/{TICKET-ID}-tech-design.md` (§4.5.6 của platform, nếu có — bảng này gộp mọi UC của platform, **lọc theo cột "
|
|
191
|
+
*Lưu ý: Với lệnh này, target ở Bước 1 là một UC-ID. Đọc `.feature` FE của UC (web/app), các màn Design Spec của nó, tech-doc gộp `{paths.tech_docs_dir}/{domain}/{prd-slug}/tech-docs/{TICKET-ID}-tech-design.md` (§4.5.6 của platform, nếu có — bảng này gộp mọi UC của platform, **lọc theo cột "Phục vụ SC" khớp SC của UC này** qua §10), và figma-components catalog cho `active_module`.*
|
|
168
192
|
|
|
169
193
|
## Context
|
|
170
194
|
**BẮT BUỘC — đọc `.agent/steps/context-loader.md` và thực thi TOÀN BỘ quy trình trong đó**,
|
|
@@ -188,8 +212,15 @@ Phân giải attribute test-id từ `@trace.testid_attr` (hoặc theo module): w
|
|
|
188
212
|
|
|
189
213
|
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
214
|
- **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).
|
|
215
|
+
- **existing** — component riêng của feature đã có trong codebase (brownfield); *chỉ gặp ở `--from-code`*;
|
|
216
|
+
- **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.*
|
|
217
|
+
|
|
218
|
+
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**
|
|
219
|
+
(xem Step 5): nó đổi theo thời gian, một element `new` thành `existing` ngay khi dev viết code.
|
|
220
|
+
|
|
221
|
+
**Cột `Component` của bảng** lấy từ **§4.5.1 Cây Component trong chính tech-doc này** (do
|
|
222
|
+
`/generate-tech-docs` vẽ từ design-spec) — trỏ `§4.5.1.x`. §4.5.1 chưa có (ca `--from-code` ghi
|
|
223
|
+
file tối thiểu) thì ghi tên component.
|
|
193
224
|
|
|
194
225
|
## Step 2 — Phân giải test-id ổn định cho mỗi element
|
|
195
226
|
|
|
@@ -197,7 +228,7 @@ Từ các step `When` trong `.feature` FE của UC + các màn Design Spec, li
|
|
|
197
228
|
- **Reused:** id được áp ở **usage site** (không bake vào component dùng chung) → gán theo cùng quy ước.
|
|
198
229
|
- **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
230
|
|
|
200
|
-
## Step 3 — Đảm bảo component tái dùng forward được test-id (catalog)
|
|
231
|
+
## Step 3 — Đảm bảo component tái dùng forward được test-id (catalog) *(chỉ `--from-code`)*
|
|
201
232
|
|
|
202
233
|
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
234
|
- **Đã ghi prop forwarding** → dùng nó ở usage site (Step 4).
|
|
@@ -207,17 +238,66 @@ Với mỗi component **reused** có action, tra section **`## Test-ID Forwardin
|
|
|
207
238
|
|
|
208
239
|
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
240
|
|
|
210
|
-
## Step 4 — Patch usage site (chỉ EXTEND)
|
|
241
|
+
## Step 4 — Patch usage site (chỉ EXTEND) *(chỉ `--from-code`)*
|
|
211
242
|
|
|
212
243
|
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
244
|
|
|
214
245
|
## Step 5 — Ghi/làm mới map §4.5.6 Test Selectors
|
|
215
246
|
|
|
216
247
|
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 →
|
|
248
|
+
- Nếu tech-doc tồn tại → **hai việc, không bỏ việc nào**:
|
|
249
|
+
- **(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 đè.
|
|
250
|
+
- **(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
251
|
- 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
252
|
|
|
220
|
-
|
|
253
|
+
> **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.
|
|
254
|
+
|
|
255
|
+
Mỗi row — **5 cột, đúng thứ tự của template** (`templates/tech-design.template.md` §4.5.6):
|
|
256
|
+
|
|
257
|
+
`Test-ID | Element | Component | Action | Phục vụ SC (UC · SC)`
|
|
258
|
+
|
|
259
|
+
- **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.
|
|
260
|
+
- **Phục vụ 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.
|
|
261
|
+
|
|
262
|
+
> **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.
|
|
263
|
+
>
|
|
264
|
+
> **Thứ tự cột là load-bearing:** `lint-trace` **T15** đọc cột "Phục vụ 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 ô.
|
|
265
|
+
|
|
266
|
+
## Step 5b — Làm mất hiệu lực `qc_status` của SC bị ảnh hưởng *(chỉ khi ĐỔI id đã có)*
|
|
267
|
+
|
|
268
|
+
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
|
|
269
|
+
không kích hoạt bước này — chưa có script nào bám id mới).
|
|
270
|
+
|
|
271
|
+
Đổ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
|
|
272
|
+
mang id đó. Giữ `qc_status = pass` ở đó là **báo cáo sai** — `rules/workflow.md` §*"Làm mất hiệu
|
|
273
|
+
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'"*.
|
|
274
|
+
|
|
275
|
+
```
|
|
276
|
+
với mỗi id ĐỔI:
|
|
277
|
+
đọc cột "Phục vụ SC" của row đó → danh sách {UC-ID}-SC{N}
|
|
278
|
+
mở sổ {paths.trace_dir}/{domain}/{prd-slug}/{UC-ID}-{platform}.tsv
|
|
279
|
+
với mỗi SC trong danh sách:
|
|
280
|
+
qc_status → not_run (chỉ hạ từ `pass`/`fail`; đang `not_run`/`skip` thì để yên)
|
|
281
|
+
qc_run_at → —
|
|
282
|
+
```
|
|
283
|
+
|
|
284
|
+
**KHÔNG đụng `qc_owner` và `qc_blocked_by`.** `rules/workflow.md` miễn trừ tường minh hai cột
|
|
285
|
+
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
|
|
286
|
+
đường về bug đang mở.
|
|
287
|
+
|
|
288
|
+
**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ổ.
|
|
289
|
+
|
|
290
|
+
In ra ở report:
|
|
291
|
+
```
|
|
292
|
+
⚠️ {n} scenario có script QC bám id CŨ — qc_status hạ về not_run: {danh sách SC}
|
|
293
|
+
Chạy /qc-design-test (hoặc /qc-run-test) lại cho các UC đó.
|
|
294
|
+
```
|
|
295
|
+
|
|
296
|
+
> **Vì sao hạ chứ không giữ.** `rules/workflow.md`: *"`pass` **không** mang nghĩa 'test đã chạy
|
|
297
|
+
> xanh' — nó mang nghĩa 'scenario này đã được nghiệm thu theo spec **hiện tại**'."* Một script
|
|
298
|
+
> đị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
|
|
299
|
+
> 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ì
|
|
300
|
+
> `pass` — không phải học cơ chế mới nào.
|
|
221
301
|
|
|
222
302
|
## Step 6 — Handoff
|
|
223
303
|
|