@educa-corp/sdd-framework 0.4.0 → 0.4.2

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.
Files changed (123) hide show
  1. package/bin/build.js +9 -0
  2. package/bin/index.js +115 -4
  3. package/bin/self-check.js +236 -0
  4. package/bin/trace-schema.json +692 -0
  5. package/commands/debug.md +16 -10
  6. package/commands/define-product.md +16 -10
  7. package/commands/dev-gen-test.md +16 -10
  8. package/commands/dev-run-test.md +18 -11
  9. package/commands/dev-run-test.tmpl +2 -1
  10. package/commands/dev-smoke-test.md +16 -10
  11. package/commands/fix-bug.md +71 -13
  12. package/commands/fix-bug.tmpl +29 -3
  13. package/commands/generate-architecture.md +16 -10
  14. package/commands/generate-bdd.md +118 -35
  15. package/commands/generate-bdd.tmpl +89 -15
  16. package/commands/generate-code.md +49 -13
  17. package/commands/generate-code.tmpl +33 -3
  18. package/commands/generate-design-spec.md +16 -10
  19. package/commands/generate-prd.md +16 -10
  20. package/commands/generate-spec-manifest.md +16 -10
  21. package/commands/generate-tech-docs.md +19 -13
  22. package/commands/generate-tech-docs.tmpl +2 -2
  23. package/commands/learn.md +16 -10
  24. package/commands/map-testids.md +16 -10
  25. package/commands/propose-scenario.md +36 -12
  26. package/commands/propose-scenario.tmpl +20 -2
  27. package/commands/qc-analyze.md +16 -10
  28. package/commands/qc-design-test.md +16 -10
  29. package/commands/qc-plan.md +16 -10
  30. package/commands/qc-report.md +16 -10
  31. package/commands/qc-review.md +16 -10
  32. package/commands/qc-run-test.md +38 -12
  33. package/commands/qc-run-test.tmpl +22 -2
  34. package/commands/refine-prd.md +16 -10
  35. package/commands/report-bug.md +16 -10
  36. package/commands/review-code.md +56 -12
  37. package/commands/review-code.tmpl +40 -2
  38. package/commands/review-context.md +58 -14
  39. package/commands/review-context.tmpl +42 -4
  40. package/commands/review-tech-docs.md +47 -12
  41. package/commands/review-tech-docs.tmpl +31 -2
  42. package/commands/setup-ai-first.md +23 -14
  43. package/commands/setup-ai-first.tmpl +7 -4
  44. package/commands/sync.md +3 -2
  45. package/commands/update-framework.md +40 -2
  46. package/commands/update-framework.tmpl +37 -0
  47. package/commands/validate-traces.md +165 -18
  48. package/commands/validate-traces.tmpl +149 -8
  49. package/core/FRAMEWORK_VERSION +1 -1
  50. package/core/README.md +56 -0
  51. package/core/commands/debug.md +16 -10
  52. package/core/commands/define-product.md +16 -10
  53. package/core/commands/dev-gen-test.md +16 -10
  54. package/core/commands/dev-run-test.md +18 -11
  55. package/core/commands/dev-smoke-test.md +16 -10
  56. package/core/commands/fix-bug.md +71 -13
  57. package/core/commands/generate-architecture.md +16 -10
  58. package/core/commands/generate-bdd.md +118 -35
  59. package/core/commands/generate-code.md +49 -13
  60. package/core/commands/generate-design-spec.md +16 -10
  61. package/core/commands/generate-prd.md +16 -10
  62. package/core/commands/generate-spec-manifest.md +16 -10
  63. package/core/commands/generate-tech-docs.md +19 -13
  64. package/core/commands/learn.md +16 -10
  65. package/core/commands/map-testids.md +16 -10
  66. package/core/commands/propose-scenario.md +36 -12
  67. package/core/commands/qc-analyze.md +16 -10
  68. package/core/commands/qc-design-test.md +16 -10
  69. package/core/commands/qc-plan.md +16 -10
  70. package/core/commands/qc-report.md +16 -10
  71. package/core/commands/qc-review.md +16 -10
  72. package/core/commands/qc-run-test.md +38 -12
  73. package/core/commands/refine-prd.md +16 -10
  74. package/core/commands/report-bug.md +16 -10
  75. package/core/commands/review-code.md +56 -12
  76. package/core/commands/review-context.md +58 -14
  77. package/core/commands/review-tech-docs.md +47 -12
  78. package/core/commands/setup-ai-first.md +23 -14
  79. package/core/commands/sync.md +3 -2
  80. package/core/commands/update-framework.md +40 -2
  81. package/core/commands/validate-traces.md +165 -18
  82. package/core/modules/android-compose/stack-profile.yaml +1 -1
  83. package/core/modules/flutter/stack-profile.yaml +1 -1
  84. package/core/modules/ios-swiftui/stack-profile.yaml +1 -1
  85. package/core/modules/java-spring/stack-profile.yaml +1 -1
  86. package/core/modules/nextjs/stack-profile.yaml +1 -1
  87. package/core/modules/nuxt/stack-profile.yaml +1 -1
  88. package/core/modules/phaser-game/stack-profile.yaml +1 -1
  89. package/core/modules/php-laravel/stack-profile.yaml +1 -1
  90. package/core/modules/qc-playwright/stack-profile.yaml +1 -1
  91. package/core/modules/react/stack-profile.yaml +1 -1
  92. package/core/modules/react-native/stack-profile.yaml +1 -1
  93. package/core/modules/vue/stack-profile.yaml +1 -1
  94. package/core/rules/workflow.md +11 -0
  95. package/core/steps/gate.md +13 -8
  96. package/core/steps/report-footer.md +3 -2
  97. package/core/templates/README.md +47 -0
  98. package/core/templates/feature.template +13 -10
  99. package/core/templates/project-context.yaml +26 -14
  100. package/core/templates/tech-design.template.md +1 -1
  101. package/docs/02-concepts/traceability.md +29 -6
  102. package/docs/04-reference/trace-schema.md +128 -37
  103. package/modules/android-compose/stack-profile.yaml +1 -1
  104. package/modules/flutter/stack-profile.yaml +1 -1
  105. package/modules/ios-swiftui/stack-profile.yaml +1 -1
  106. package/modules/java-spring/stack-profile.yaml +1 -1
  107. package/modules/nextjs/stack-profile.yaml +1 -1
  108. package/modules/nuxt/stack-profile.yaml +1 -1
  109. package/modules/phaser-game/stack-profile.yaml +1 -1
  110. package/modules/php-laravel/stack-profile.yaml +1 -1
  111. package/modules/qc-playwright/stack-profile.yaml +1 -1
  112. package/modules/react/stack-profile.yaml +1 -1
  113. package/modules/react-native/stack-profile.yaml +1 -1
  114. package/modules/vue/stack-profile.yaml +1 -1
  115. package/package.json +50 -49
  116. package/rules/workflow.md +11 -0
  117. package/scripts/migrate-bdd-platform.js +286 -0
  118. package/steps/gate.md +13 -8
  119. package/steps/report-footer.md +3 -2
  120. package/templates/README.md +47 -0
  121. package/templates/feature.template +13 -10
  122. package/templates/project-context.yaml +26 -14
  123. package/templates/tech-design.template.md +1 -1
package/commands/debug.md CHANGED
@@ -35,23 +35,23 @@ Hiển thị và chờ phản hồi:
35
35
  ```
36
36
  ⚙️ MODEL CHECK
37
37
  ──────────────────────────────────────────────────────────────────
38
- Recommended : claude-opus-4 (hoặc model Opus mới nhất)
38
+ Recommended : model Opus mới nhất
39
39
  Why needed : Phân tích spec, review kiến trúc, sinh code đòi hỏi
40
- suy luận sâu. Model nhỏ hơn dễ bỏ sót edge case.
40
+ suy luận sâu. Model nhỏ hơn (Haiku/Sonnet) dễ bỏ sót edge case.
41
41
 
42
42
  Cách đổi trong Claude Code:
43
- SettingsModel chọn "claude-opus"
44
- • hoặc: /modelchọn claude-opus
43
+ /modelchọn model Opus
44
+ • hoặc: SettingsModel
45
45
 
46
- Đang chạy claude-opus?
47
- Y — đúng, đang dùng claude-opus → tiếp tục
46
+ Đang chạy một model Opus?
47
+ Y — đúng → tiếp tục
48
48
  S — bỏ qua kiểm tra (tôi chấp nhận rủi ro chất lượng thấp hơn với model hiện tại)
49
49
  ──────────────────────────────────────────────────────────────────
50
50
  ```
51
51
 
52
52
  - "Y" → tiếp tục sang Bước 1.
53
53
  - "S" → tiếp tục sang Bước 1 (người dùng chấp nhận rủi ro, thêm ⚠️ vào report cuối).
54
- - "N" hoặc bất kỳ giá trị nào khác → **DỪNG.** Xuất: "Vui lòng chuyển sang claude-opus rồi chạy lại lệnh này."
54
+ - "N" hoặc bất kỳ giá trị nào khác → **DỪNG.** Xuất: "Vui lòng chuyển sang một model Opus (`/model`) rồi chạy lại lệnh này."
55
55
 
56
56
  ## Bước 1 — Xác định Target File
57
57
 
@@ -60,7 +60,12 @@ Hiển thị và chờ phản hồi:
60
60
  2. Nếu `$ARGUMENTS` là một **UC-ID / ticket ID / tên rút gọn** (không có path) → phân giải thành file bằng cách glob theo bố cục feature-package. `{prd-slug}` lúc này **chưa biết**, nên dùng wildcard `*` cho segment đó, và `**` đệ quy dưới `bdd/` để phủ hết các thư mục con theo platform (`bdd/web/`, `bdd/app/`, `bdd/system/`):
61
61
  - **Lệnh BDD** (target là `.feature`): `{specs_dir}/{domain}/*/bdd/**/{UC-ID}*.feature` — hoặc `{specs_dir}/*/*/bdd/**/{UC-ID}*.feature` nếu domain cũng chưa biết. Nếu lệnh ngụ ý một platform/scope cụ thể (vd: system tech-doc cần BDD `system/`), ưu tiên kết quả trong thư mục con platform đó.
62
62
  - **Lệnh PRD** (target là file PRD `{TICKET-ID}-{prd-slug}.md` — file `.md` duy nhất ở gốc feature folder, cạnh `bdd/`): `{specs_dir}/{domain}/*/{TICKET-ID}*.md` nếu biết TICKET-ID; nếu không, `{specs_dir}/{domain}/*/*.md` (khớp feature folder có id tương ứng), hoặc `{specs_dir}/*/*/*.md` nếu domain cũng chưa biết. *(Glob `*/*.md` ở cấp gốc folder chỉ khớp PRD — tech-docs/design-spec `.md` nằm sâu hơn trong thư mục con.)*
63
- - **Lệnh tech-docs**: `{specs_dir}/{domain}/*/tech-docs/{UC-ID}*-tech-design*.md`.
63
+ - **Lệnh tech-docs** — target là tech-doc **gộp cấp PRD** `{TICKET-ID}-tech-design.md` (MỘT doc phủ nhiều UC; danh sách UC nằm ở `@trace.ucs`). Vì tên file mang `{TICKET-ID}` chứ **không** mang `{UC-ID}`, phải tách trước khi glob:
64
+ - `$ARGUMENTS` là **UC-ID** (`{TICKET-ID}-UC{N}`) → lấy `{TICKET-ID}` = phần **trước** `-UC`, rồi glob `{specs_dir}/{domain}/*/tech-docs/{TICKET-ID}-tech-design.md`.
65
+ - `$ARGUMENTS` là **TICKET-ID** → glob trực tiếp như trên.
66
+ - Chưa biết domain → `{specs_dir}/*/*/tech-docs/{TICKET-ID}-tech-design.md`.
67
+ - Vẫn không khớp → glob rộng `{specs_dir}/*/*/tech-docs/*tech-design*.md` rồi liệt kê để người dùng chọn.
68
+ *(Đừng glob `{UC-ID}*-tech-design*.md` — nó nở thành `FT-001-UC1*-tech-design*.md` và **không bao giờ** khớp `FT-001-tech-design.md`.)*
64
69
  - **Lệnh design-spec**: `{specs_dir}/{domain}/*/design-spec/{TICKET-ID}*.md`.
65
70
 
66
71
  Khi một file khớp: đặt nó làm target **và** ghi lại `domain` + `prd_slug` từ path của nó (theo quy tắc trích xuất trong `context-loader.md` Bước 1 — `prd_slug` = segment đầu tiên sau `{specs_dir}/{domain}/`). Mọi path mà lệnh đọc/ghi về sau (BDD/tech-docs/design-spec/trace cùng cấp) đều dùng **`prd_slug` đã phân giải đó**, nên tất cả artifact nằm chung một feature package. Nếu nhiều file khớp (vd: nhiều platform), chọn theo platform/scope của lệnh hoặc liệt kê ra và hỏi.
@@ -762,6 +767,7 @@ Gợi ý lệnh kế tiếp hợp lý theo phase của workflow:
762
767
  | /qc-run-test | `/qc-report {UC-ID}` rồi `/qc-review {UC-ID}` (review script) |
763
768
  | /qc-review (script) | `/qc-report {UC-ID}` rồi tạo PR nếu APPROVED |
764
769
  | /qc-report | `/validate-traces {UC-ID}` để làm mới Living Docs (qc_status) |
770
+ | /map-testids | `/qc-design-test {UC-ID}` (QC dựng Page Object từ contract §4.5.6 vừa ghi) |
765
771
  | /generate-tech-docs | `/review-tech-docs {tech-design-file}` |
766
772
  | /review-tech-docs | `/generate-code {feature-file}` nếu APPROVED; sửa doc nếu NEEDS_FIX |
767
773
  | /generate-code | Lần gen đầu → `/review-code {UC-ID}`; gen lại → `/dev-gen-test {UC-ID}` |
@@ -770,8 +776,8 @@ Gợi ý lệnh kế tiếp hợp lý theo phase của workflow:
770
776
  | /dev-run-test (failing) | `/fix-bug {ticket-id}` hoặc `/debug {error}` |
771
777
  | /review-code | `/dev-smoke-test {UC-ID}` hoặc tạo PR |
772
778
  | /dev-smoke-test | Tạo PR và link tới ticket |
773
- | /validate-traces | DRIFT/UNTRACKED → `/generate-code {UC-ID}`; GAP → `/dev-gen-test {UC-ID}`; tất cả OK tạo PR |
774
- | /fix-bug | Tạo PR link tới ticket |
779
+ | /validate-traces | **Cờ 🔴 trước (chặn PR):** SEAM_UNWIRED → nối binding sang class thật, xoá/thay stub · STUB_UNRESOLVED → `/generate-code {owner_uc}` (lấp logic tại chỗ + xoá hàm song song) · ORPHANED/TRACE_ORPHAN → quyết định thủ công (xoá code+test, đưa scenario trở lại `.feature`, hoặc sửa `sc_id` của tag). **Rồi:** DRIFT/UNTRACKED → `/generate-code {UC-ID}` · BDD_DRIFT → `/generate-code {feature-file}` · tech-doc lỗi thời vs BDD → `/generate-tech-docs` → `/review-tech-docs` · PRD drift → `/generate-bdd {prd-file}` · GAP → `/dev-gen-test {UC-ID}`. **Chỉ tạo PR khi mọi cờ 🔴 = 0** |
780
+ | /fix-bug | `/dev-run-test {UC-ID}` (dev_selftest vừa reset về not_run) → tạo PR; nếu fix một `{BUG-ID}` → QC chạy `/qc-run-test {UC-ID}` để verify + đóng bug |
775
781
  | /debug | `/fix-bug {ticket-id}` nếu cần sửa |
776
782
  | /report-bug | Gửi cho dev (`/fix-bug {BUG-ID}`); nếu thiếu coverage → `/propose-scenario {UC-ID}` |
777
783
  | /propose-scenario | Báo PO/Dev review proposal trong `feedback/bdd-proposals/` |
@@ -32,23 +32,23 @@ Hiển thị và chờ phản hồi:
32
32
  ```
33
33
  ⚙️ MODEL CHECK
34
34
  ──────────────────────────────────────────────────────────────────
35
- Recommended : claude-opus-4 (hoặc model Opus mới nhất)
35
+ Recommended : model Opus mới nhất
36
36
  Why needed : Phân tích spec, review kiến trúc, sinh code đòi hỏi
37
- suy luận sâu. Model nhỏ hơn dễ bỏ sót edge case.
37
+ suy luận sâu. Model nhỏ hơn (Haiku/Sonnet) dễ bỏ sót edge case.
38
38
 
39
39
  Cách đổi trong Claude Code:
40
- SettingsModel chọn "claude-opus"
41
- • hoặc: /modelchọn claude-opus
40
+ /modelchọn model Opus
41
+ • hoặc: SettingsModel
42
42
 
43
- Đang chạy claude-opus?
44
- Y — đúng, đang dùng claude-opus → tiếp tục
43
+ Đang chạy một model Opus?
44
+ Y — đúng → tiếp tục
45
45
  S — bỏ qua kiểm tra (tôi chấp nhận rủi ro chất lượng thấp hơn với model hiện tại)
46
46
  ──────────────────────────────────────────────────────────────────
47
47
  ```
48
48
 
49
49
  - "Y" → tiếp tục sang Bước 1.
50
50
  - "S" → tiếp tục sang Bước 1 (người dùng chấp nhận rủi ro, thêm ⚠️ vào report cuối).
51
- - "N" hoặc bất kỳ giá trị nào khác → **DỪNG.** Xuất: "Vui lòng chuyển sang claude-opus rồi chạy lại lệnh này."
51
+ - "N" hoặc bất kỳ giá trị nào khác → **DỪNG.** Xuất: "Vui lòng chuyển sang một model Opus (`/model`) rồi chạy lại lệnh này."
52
52
 
53
53
  ## Bước 1 — Xác định Target File
54
54
 
@@ -57,7 +57,12 @@ Hiển thị và chờ phản hồi:
57
57
  2. Nếu `$ARGUMENTS` là một **UC-ID / ticket ID / tên rút gọn** (không có path) → phân giải thành file bằng cách glob theo bố cục feature-package. `{prd-slug}` lúc này **chưa biết**, nên dùng wildcard `*` cho segment đó, và `**` đệ quy dưới `bdd/` để phủ hết các thư mục con theo platform (`bdd/web/`, `bdd/app/`, `bdd/system/`):
58
58
  - **Lệnh BDD** (target là `.feature`): `{specs_dir}/{domain}/*/bdd/**/{UC-ID}*.feature` — hoặc `{specs_dir}/*/*/bdd/**/{UC-ID}*.feature` nếu domain cũng chưa biết. Nếu lệnh ngụ ý một platform/scope cụ thể (vd: system tech-doc cần BDD `system/`), ưu tiên kết quả trong thư mục con platform đó.
59
59
  - **Lệnh PRD** (target là file PRD `{TICKET-ID}-{prd-slug}.md` — file `.md` duy nhất ở gốc feature folder, cạnh `bdd/`): `{specs_dir}/{domain}/*/{TICKET-ID}*.md` nếu biết TICKET-ID; nếu không, `{specs_dir}/{domain}/*/*.md` (khớp feature folder có id tương ứng), hoặc `{specs_dir}/*/*/*.md` nếu domain cũng chưa biết. *(Glob `*/*.md` ở cấp gốc folder chỉ khớp PRD — tech-docs/design-spec `.md` nằm sâu hơn trong thư mục con.)*
60
- - **Lệnh tech-docs**: `{specs_dir}/{domain}/*/tech-docs/{UC-ID}*-tech-design*.md`.
60
+ - **Lệnh tech-docs** — target là tech-doc **gộp cấp PRD** `{TICKET-ID}-tech-design.md` (MỘT doc phủ nhiều UC; danh sách UC nằm ở `@trace.ucs`). Vì tên file mang `{TICKET-ID}` chứ **không** mang `{UC-ID}`, phải tách trước khi glob:
61
+ - `$ARGUMENTS` là **UC-ID** (`{TICKET-ID}-UC{N}`) → lấy `{TICKET-ID}` = phần **trước** `-UC`, rồi glob `{specs_dir}/{domain}/*/tech-docs/{TICKET-ID}-tech-design.md`.
62
+ - `$ARGUMENTS` là **TICKET-ID** → glob trực tiếp như trên.
63
+ - Chưa biết domain → `{specs_dir}/*/*/tech-docs/{TICKET-ID}-tech-design.md`.
64
+ - Vẫn không khớp → glob rộng `{specs_dir}/*/*/tech-docs/*tech-design*.md` rồi liệt kê để người dùng chọn.
65
+ *(Đừng glob `{UC-ID}*-tech-design*.md` — nó nở thành `FT-001-UC1*-tech-design*.md` và **không bao giờ** khớp `FT-001-tech-design.md`.)*
61
66
  - **Lệnh design-spec**: `{specs_dir}/{domain}/*/design-spec/{TICKET-ID}*.md`.
62
67
 
63
68
  Khi một file khớp: đặt nó làm target **và** ghi lại `domain` + `prd_slug` từ path của nó (theo quy tắc trích xuất trong `context-loader.md` Bước 1 — `prd_slug` = segment đầu tiên sau `{specs_dir}/{domain}/`). Mọi path mà lệnh đọc/ghi về sau (BDD/tech-docs/design-spec/trace cùng cấp) đều dùng **`prd_slug` đã phân giải đó**, nên tất cả artifact nằm chung một feature package. Nếu nhiều file khớp (vd: nhiều platform), chọn theo platform/scope của lệnh hoặc liệt kê ra và hỏi.
@@ -814,6 +819,7 @@ Gợi ý lệnh kế tiếp hợp lý theo phase của workflow:
814
819
  | /qc-run-test | `/qc-report {UC-ID}` rồi `/qc-review {UC-ID}` (review script) |
815
820
  | /qc-review (script) | `/qc-report {UC-ID}` rồi tạo PR nếu APPROVED |
816
821
  | /qc-report | `/validate-traces {UC-ID}` để làm mới Living Docs (qc_status) |
822
+ | /map-testids | `/qc-design-test {UC-ID}` (QC dựng Page Object từ contract §4.5.6 vừa ghi) |
817
823
  | /generate-tech-docs | `/review-tech-docs {tech-design-file}` |
818
824
  | /review-tech-docs | `/generate-code {feature-file}` nếu APPROVED; sửa doc nếu NEEDS_FIX |
819
825
  | /generate-code | Lần gen đầu → `/review-code {UC-ID}`; gen lại → `/dev-gen-test {UC-ID}` |
@@ -822,8 +828,8 @@ Gợi ý lệnh kế tiếp hợp lý theo phase của workflow:
822
828
  | /dev-run-test (failing) | `/fix-bug {ticket-id}` hoặc `/debug {error}` |
823
829
  | /review-code | `/dev-smoke-test {UC-ID}` hoặc tạo PR |
824
830
  | /dev-smoke-test | Tạo PR và link tới ticket |
825
- | /validate-traces | DRIFT/UNTRACKED → `/generate-code {UC-ID}`; GAP → `/dev-gen-test {UC-ID}`; tất cả OK tạo PR |
826
- | /fix-bug | Tạo PR link tới ticket |
831
+ | /validate-traces | **Cờ 🔴 trước (chặn PR):** SEAM_UNWIRED → nối binding sang class thật, xoá/thay stub · STUB_UNRESOLVED → `/generate-code {owner_uc}` (lấp logic tại chỗ + xoá hàm song song) · ORPHANED/TRACE_ORPHAN → quyết định thủ công (xoá code+test, đưa scenario trở lại `.feature`, hoặc sửa `sc_id` của tag). **Rồi:** DRIFT/UNTRACKED → `/generate-code {UC-ID}` · BDD_DRIFT → `/generate-code {feature-file}` · tech-doc lỗi thời vs BDD → `/generate-tech-docs` → `/review-tech-docs` · PRD drift → `/generate-bdd {prd-file}` · GAP → `/dev-gen-test {UC-ID}`. **Chỉ tạo PR khi mọi cờ 🔴 = 0** |
832
+ | /fix-bug | `/dev-run-test {UC-ID}` (dev_selftest vừa reset về not_run) → tạo PR; nếu fix một `{BUG-ID}` → QC chạy `/qc-run-test {UC-ID}` để verify + đóng bug |
827
833
  | /debug | `/fix-bug {ticket-id}` nếu cần sửa |
828
834
  | /report-bug | Gửi cho dev (`/fix-bug {BUG-ID}`); nếu thiếu coverage → `/propose-scenario {UC-ID}` |
829
835
  | /propose-scenario | Báo PO/Dev review proposal trong `feedback/bdd-proposals/` |
@@ -38,23 +38,23 @@ Hiển thị và chờ phản hồi:
38
38
  ```
39
39
  ⚙️ MODEL CHECK
40
40
  ──────────────────────────────────────────────────────────────────
41
- Recommended : claude-opus-4 (hoặc model Opus mới nhất)
41
+ Recommended : model Opus mới nhất
42
42
  Why needed : Phân tích spec, review kiến trúc, sinh code đòi hỏi
43
- suy luận sâu. Model nhỏ hơn dễ bỏ sót edge case.
43
+ suy luận sâu. Model nhỏ hơn (Haiku/Sonnet) dễ bỏ sót edge case.
44
44
 
45
45
  Cách đổi trong Claude Code:
46
- SettingsModel chọn "claude-opus"
47
- • hoặc: /modelchọn claude-opus
46
+ /modelchọn model Opus
47
+ • hoặc: SettingsModel
48
48
 
49
- Đang chạy claude-opus?
50
- Y — đúng, đang dùng claude-opus → tiếp tục
49
+ Đang chạy một model Opus?
50
+ Y — đúng → tiếp tục
51
51
  S — bỏ qua kiểm tra (tôi chấp nhận rủi ro chất lượng thấp hơn với model hiện tại)
52
52
  ──────────────────────────────────────────────────────────────────
53
53
  ```
54
54
 
55
55
  - "Y" → tiếp tục sang Bước 1.
56
56
  - "S" → tiếp tục sang Bước 1 (người dùng chấp nhận rủi ro, thêm ⚠️ vào report cuối).
57
- - "N" hoặc bất kỳ giá trị nào khác → **DỪNG.** Xuất: "Vui lòng chuyển sang claude-opus rồi chạy lại lệnh này."
57
+ - "N" hoặc bất kỳ giá trị nào khác → **DỪNG.** Xuất: "Vui lòng chuyển sang một model Opus (`/model`) rồi chạy lại lệnh này."
58
58
 
59
59
  ## Bước 1 — Xác định Target File
60
60
 
@@ -63,7 +63,12 @@ Hiển thị và chờ phản hồi:
63
63
  2. Nếu `$ARGUMENTS` là một **UC-ID / ticket ID / tên rút gọn** (không có path) → phân giải thành file bằng cách glob theo bố cục feature-package. `{prd-slug}` lúc này **chưa biết**, nên dùng wildcard `*` cho segment đó, và `**` đệ quy dưới `bdd/` để phủ hết các thư mục con theo platform (`bdd/web/`, `bdd/app/`, `bdd/system/`):
64
64
  - **Lệnh BDD** (target là `.feature`): `{specs_dir}/{domain}/*/bdd/**/{UC-ID}*.feature` — hoặc `{specs_dir}/*/*/bdd/**/{UC-ID}*.feature` nếu domain cũng chưa biết. Nếu lệnh ngụ ý một platform/scope cụ thể (vd: system tech-doc cần BDD `system/`), ưu tiên kết quả trong thư mục con platform đó.
65
65
  - **Lệnh PRD** (target là file PRD `{TICKET-ID}-{prd-slug}.md` — file `.md` duy nhất ở gốc feature folder, cạnh `bdd/`): `{specs_dir}/{domain}/*/{TICKET-ID}*.md` nếu biết TICKET-ID; nếu không, `{specs_dir}/{domain}/*/*.md` (khớp feature folder có id tương ứng), hoặc `{specs_dir}/*/*/*.md` nếu domain cũng chưa biết. *(Glob `*/*.md` ở cấp gốc folder chỉ khớp PRD — tech-docs/design-spec `.md` nằm sâu hơn trong thư mục con.)*
66
- - **Lệnh tech-docs**: `{specs_dir}/{domain}/*/tech-docs/{UC-ID}*-tech-design*.md`.
66
+ - **Lệnh tech-docs** — target là tech-doc **gộp cấp PRD** `{TICKET-ID}-tech-design.md` (MỘT doc phủ nhiều UC; danh sách UC nằm ở `@trace.ucs`). Vì tên file mang `{TICKET-ID}` chứ **không** mang `{UC-ID}`, phải tách trước khi glob:
67
+ - `$ARGUMENTS` là **UC-ID** (`{TICKET-ID}-UC{N}`) → lấy `{TICKET-ID}` = phần **trước** `-UC`, rồi glob `{specs_dir}/{domain}/*/tech-docs/{TICKET-ID}-tech-design.md`.
68
+ - `$ARGUMENTS` là **TICKET-ID** → glob trực tiếp như trên.
69
+ - Chưa biết domain → `{specs_dir}/*/*/tech-docs/{TICKET-ID}-tech-design.md`.
70
+ - Vẫn không khớp → glob rộng `{specs_dir}/*/*/tech-docs/*tech-design*.md` rồi liệt kê để người dùng chọn.
71
+ *(Đừng glob `{UC-ID}*-tech-design*.md` — nó nở thành `FT-001-UC1*-tech-design*.md` và **không bao giờ** khớp `FT-001-tech-design.md`.)*
67
72
  - **Lệnh design-spec**: `{specs_dir}/{domain}/*/design-spec/{TICKET-ID}*.md`.
68
73
 
69
74
  Khi một file khớp: đặt nó làm target **và** ghi lại `domain` + `prd_slug` từ path của nó (theo quy tắc trích xuất trong `context-loader.md` Bước 1 — `prd_slug` = segment đầu tiên sau `{specs_dir}/{domain}/`). Mọi path mà lệnh đọc/ghi về sau (BDD/tech-docs/design-spec/trace cùng cấp) đều dùng **`prd_slug` đã phân giải đó**, nên tất cả artifact nằm chung một feature package. Nếu nhiều file khớp (vd: nhiều platform), chọn theo platform/scope của lệnh hoặc liệt kê ra và hỏi.
@@ -1050,6 +1055,7 @@ Gợi ý lệnh kế tiếp hợp lý theo phase của workflow:
1050
1055
  | /qc-run-test | `/qc-report {UC-ID}` rồi `/qc-review {UC-ID}` (review script) |
1051
1056
  | /qc-review (script) | `/qc-report {UC-ID}` rồi tạo PR nếu APPROVED |
1052
1057
  | /qc-report | `/validate-traces {UC-ID}` để làm mới Living Docs (qc_status) |
1058
+ | /map-testids | `/qc-design-test {UC-ID}` (QC dựng Page Object từ contract §4.5.6 vừa ghi) |
1053
1059
  | /generate-tech-docs | `/review-tech-docs {tech-design-file}` |
1054
1060
  | /review-tech-docs | `/generate-code {feature-file}` nếu APPROVED; sửa doc nếu NEEDS_FIX |
1055
1061
  | /generate-code | Lần gen đầu → `/review-code {UC-ID}`; gen lại → `/dev-gen-test {UC-ID}` |
@@ -1058,8 +1064,8 @@ Gợi ý lệnh kế tiếp hợp lý theo phase của workflow:
1058
1064
  | /dev-run-test (failing) | `/fix-bug {ticket-id}` hoặc `/debug {error}` |
1059
1065
  | /review-code | `/dev-smoke-test {UC-ID}` hoặc tạo PR |
1060
1066
  | /dev-smoke-test | Tạo PR và link tới ticket |
1061
- | /validate-traces | DRIFT/UNTRACKED → `/generate-code {UC-ID}`; GAP → `/dev-gen-test {UC-ID}`; tất cả OK tạo PR |
1062
- | /fix-bug | Tạo PR link tới ticket |
1067
+ | /validate-traces | **Cờ 🔴 trước (chặn PR):** SEAM_UNWIRED → nối binding sang class thật, xoá/thay stub · STUB_UNRESOLVED → `/generate-code {owner_uc}` (lấp logic tại chỗ + xoá hàm song song) · ORPHANED/TRACE_ORPHAN → quyết định thủ công (xoá code+test, đưa scenario trở lại `.feature`, hoặc sửa `sc_id` của tag). **Rồi:** DRIFT/UNTRACKED → `/generate-code {UC-ID}` · BDD_DRIFT → `/generate-code {feature-file}` · tech-doc lỗi thời vs BDD → `/generate-tech-docs` → `/review-tech-docs` · PRD drift → `/generate-bdd {prd-file}` · GAP → `/dev-gen-test {UC-ID}`. **Chỉ tạo PR khi mọi cờ 🔴 = 0** |
1068
+ | /fix-bug | `/dev-run-test {UC-ID}` (dev_selftest vừa reset về not_run) → tạo PR; nếu fix một `{BUG-ID}` → QC chạy `/qc-run-test {UC-ID}` để verify + đóng bug |
1063
1069
  | /debug | `/fix-bug {ticket-id}` nếu cần sửa |
1064
1070
  | /report-bug | Gửi cho dev (`/fix-bug {BUG-ID}`); nếu thiếu coverage → `/propose-scenario {UC-ID}` |
1065
1071
  | /propose-scenario | Báo PO/Dev review proposal trong `feedback/bdd-proposals/` |
@@ -38,23 +38,23 @@ Hiển thị và chờ phản hồi:
38
38
  ```
39
39
  ⚙️ MODEL CHECK
40
40
  ──────────────────────────────────────────────────────────────────
41
- Recommended : claude-opus-4 (hoặc model Opus mới nhất)
41
+ Recommended : model Opus mới nhất
42
42
  Why needed : Phân tích spec, review kiến trúc, sinh code đòi hỏi
43
- suy luận sâu. Model nhỏ hơn dễ bỏ sót edge case.
43
+ suy luận sâu. Model nhỏ hơn (Haiku/Sonnet) dễ bỏ sót edge case.
44
44
 
45
45
  Cách đổi trong Claude Code:
46
- SettingsModel chọn "claude-opus"
47
- • hoặc: /modelchọn claude-opus
46
+ /modelchọn model Opus
47
+ • hoặc: SettingsModel
48
48
 
49
- Đang chạy claude-opus?
50
- Y — đúng, đang dùng claude-opus → tiếp tục
49
+ Đang chạy một model Opus?
50
+ Y — đúng → tiếp tục
51
51
  S — bỏ qua kiểm tra (tôi chấp nhận rủi ro chất lượng thấp hơn với model hiện tại)
52
52
  ──────────────────────────────────────────────────────────────────
53
53
  ```
54
54
 
55
55
  - "Y" → tiếp tục sang Bước 1.
56
56
  - "S" → tiếp tục sang Bước 1 (người dùng chấp nhận rủi ro, thêm ⚠️ vào report cuối).
57
- - "N" hoặc bất kỳ giá trị nào khác → **DỪNG.** Xuất: "Vui lòng chuyển sang claude-opus rồi chạy lại lệnh này."
57
+ - "N" hoặc bất kỳ giá trị nào khác → **DỪNG.** Xuất: "Vui lòng chuyển sang một model Opus (`/model`) rồi chạy lại lệnh này."
58
58
 
59
59
  ## Bước 1 — Xác định Target File
60
60
 
@@ -63,7 +63,12 @@ Hiển thị và chờ phản hồi:
63
63
  2. Nếu `$ARGUMENTS` là một **UC-ID / ticket ID / tên rút gọn** (không có path) → phân giải thành file bằng cách glob theo bố cục feature-package. `{prd-slug}` lúc này **chưa biết**, nên dùng wildcard `*` cho segment đó, và `**` đệ quy dưới `bdd/` để phủ hết các thư mục con theo platform (`bdd/web/`, `bdd/app/`, `bdd/system/`):
64
64
  - **Lệnh BDD** (target là `.feature`): `{specs_dir}/{domain}/*/bdd/**/{UC-ID}*.feature` — hoặc `{specs_dir}/*/*/bdd/**/{UC-ID}*.feature` nếu domain cũng chưa biết. Nếu lệnh ngụ ý một platform/scope cụ thể (vd: system tech-doc cần BDD `system/`), ưu tiên kết quả trong thư mục con platform đó.
65
65
  - **Lệnh PRD** (target là file PRD `{TICKET-ID}-{prd-slug}.md` — file `.md` duy nhất ở gốc feature folder, cạnh `bdd/`): `{specs_dir}/{domain}/*/{TICKET-ID}*.md` nếu biết TICKET-ID; nếu không, `{specs_dir}/{domain}/*/*.md` (khớp feature folder có id tương ứng), hoặc `{specs_dir}/*/*/*.md` nếu domain cũng chưa biết. *(Glob `*/*.md` ở cấp gốc folder chỉ khớp PRD — tech-docs/design-spec `.md` nằm sâu hơn trong thư mục con.)*
66
- - **Lệnh tech-docs**: `{specs_dir}/{domain}/*/tech-docs/{UC-ID}*-tech-design*.md`.
66
+ - **Lệnh tech-docs** — target là tech-doc **gộp cấp PRD** `{TICKET-ID}-tech-design.md` (MỘT doc phủ nhiều UC; danh sách UC nằm ở `@trace.ucs`). Vì tên file mang `{TICKET-ID}` chứ **không** mang `{UC-ID}`, phải tách trước khi glob:
67
+ - `$ARGUMENTS` là **UC-ID** (`{TICKET-ID}-UC{N}`) → lấy `{TICKET-ID}` = phần **trước** `-UC`, rồi glob `{specs_dir}/{domain}/*/tech-docs/{TICKET-ID}-tech-design.md`.
68
+ - `$ARGUMENTS` là **TICKET-ID** → glob trực tiếp như trên.
69
+ - Chưa biết domain → `{specs_dir}/*/*/tech-docs/{TICKET-ID}-tech-design.md`.
70
+ - Vẫn không khớp → glob rộng `{specs_dir}/*/*/tech-docs/*tech-design*.md` rồi liệt kê để người dùng chọn.
71
+ *(Đừng glob `{UC-ID}*-tech-design*.md` — nó nở thành `FT-001-UC1*-tech-design*.md` và **không bao giờ** khớp `FT-001-tech-design.md`.)*
67
72
  - **Lệnh design-spec**: `{specs_dir}/{domain}/*/design-spec/{TICKET-ID}*.md`.
68
73
 
69
74
  Khi một file khớp: đặt nó làm target **và** ghi lại `domain` + `prd_slug` từ path của nó (theo quy tắc trích xuất trong `context-loader.md` Bước 1 — `prd_slug` = segment đầu tiên sau `{specs_dir}/{domain}/`). Mọi path mà lệnh đọc/ghi về sau (BDD/tech-docs/design-spec/trace cùng cấp) đều dùng **`prd_slug` đã phân giải đó**, nên tất cả artifact nằm chung một feature package. Nếu nhiều file khớp (vd: nhiều platform), chọn theo platform/scope của lệnh hoặc liệt kê ra và hỏi.
@@ -663,11 +668,12 @@ Cập nhật **sổ của platform đang test** `{paths.trace_dir}/{domain}/{prd
663
668
  |--------|-------|
664
669
  | `dev_selftest` | `pass` nếu mọi test của SC này pass · `fail` nếu có cái fail · `not_run` nếu test của nó bị skip/vắng |
665
670
  | `dev_selftest_at` | hôm nay `YYYY-MM-DD` |
671
+ | `last_updated` | hôm nay `YYYY-MM-DD` |
666
672
 
667
673
  Giữ nguyên mọi cột khác — đặc biệt **không bao giờ** đụng `qc_status`/`qc_run_at`
668
674
  (kết quả QC automation chính thức, do `/qc-run-test` sở hữu). `dev_selftest` (dev smoke)
669
675
  và `qc_status` (QC chính thức) là hai tín hiệu riêng. `dev_selftest`/`dev_selftest_at` cũng
670
- trực giao với `status` (OK/GAP/DRIFT/UNTRACKED): `status` theo dõi *coverage*, `dev_selftest`
676
+ trực giao với `status` (OK/GAP/DRIFT/UNTRACKED/ORPHANED): `status` theo dõi *coverage*, `dev_selftest`
671
677
  theo dõi *kết quả chạy* gần nhất của dev.
672
678
 
673
679
  ## Refresh Panel Mirror
@@ -774,6 +780,7 @@ Gợi ý lệnh kế tiếp hợp lý theo phase của workflow:
774
780
  | /qc-run-test | `/qc-report {UC-ID}` rồi `/qc-review {UC-ID}` (review script) |
775
781
  | /qc-review (script) | `/qc-report {UC-ID}` rồi tạo PR nếu APPROVED |
776
782
  | /qc-report | `/validate-traces {UC-ID}` để làm mới Living Docs (qc_status) |
783
+ | /map-testids | `/qc-design-test {UC-ID}` (QC dựng Page Object từ contract §4.5.6 vừa ghi) |
777
784
  | /generate-tech-docs | `/review-tech-docs {tech-design-file}` |
778
785
  | /review-tech-docs | `/generate-code {feature-file}` nếu APPROVED; sửa doc nếu NEEDS_FIX |
779
786
  | /generate-code | Lần gen đầu → `/review-code {UC-ID}`; gen lại → `/dev-gen-test {UC-ID}` |
@@ -782,8 +789,8 @@ Gợi ý lệnh kế tiếp hợp lý theo phase của workflow:
782
789
  | /dev-run-test (failing) | `/fix-bug {ticket-id}` hoặc `/debug {error}` |
783
790
  | /review-code | `/dev-smoke-test {UC-ID}` hoặc tạo PR |
784
791
  | /dev-smoke-test | Tạo PR và link tới ticket |
785
- | /validate-traces | DRIFT/UNTRACKED → `/generate-code {UC-ID}`; GAP → `/dev-gen-test {UC-ID}`; tất cả OK tạo PR |
786
- | /fix-bug | Tạo PR link tới ticket |
792
+ | /validate-traces | **Cờ 🔴 trước (chặn PR):** SEAM_UNWIRED → nối binding sang class thật, xoá/thay stub · STUB_UNRESOLVED → `/generate-code {owner_uc}` (lấp logic tại chỗ + xoá hàm song song) · ORPHANED/TRACE_ORPHAN → quyết định thủ công (xoá code+test, đưa scenario trở lại `.feature`, hoặc sửa `sc_id` của tag). **Rồi:** DRIFT/UNTRACKED → `/generate-code {UC-ID}` · BDD_DRIFT → `/generate-code {feature-file}` · tech-doc lỗi thời vs BDD → `/generate-tech-docs` → `/review-tech-docs` · PRD drift → `/generate-bdd {prd-file}` · GAP → `/dev-gen-test {UC-ID}`. **Chỉ tạo PR khi mọi cờ 🔴 = 0** |
793
+ | /fix-bug | `/dev-run-test {UC-ID}` (dev_selftest vừa reset về not_run) → tạo PR; nếu fix một `{BUG-ID}` → QC chạy `/qc-run-test {UC-ID}` để verify + đóng bug |
787
794
  | /debug | `/fix-bug {ticket-id}` nếu cần sửa |
788
795
  | /report-bug | Gửi cho dev (`/fix-bug {BUG-ID}`); nếu thiếu coverage → `/propose-scenario {UC-ID}` |
789
796
  | /propose-scenario | Báo PO/Dev review proposal trong `feedback/bdd-proposals/` |
@@ -189,11 +189,12 @@ Cập nhật **sổ của platform đang test** `{paths.trace_dir}/{domain}/{prd
189
189
  |--------|-------|
190
190
  | `dev_selftest` | `pass` nếu mọi test của SC này pass · `fail` nếu có cái fail · `not_run` nếu test của nó bị skip/vắng |
191
191
  | `dev_selftest_at` | hôm nay `YYYY-MM-DD` |
192
+ | `last_updated` | hôm nay `YYYY-MM-DD` |
192
193
 
193
194
  Giữ nguyên mọi cột khác — đặc biệt **không bao giờ** đụng `qc_status`/`qc_run_at`
194
195
  (kết quả QC automation chính thức, do `/qc-run-test` sở hữu). `dev_selftest` (dev smoke)
195
196
  và `qc_status` (QC chính thức) là hai tín hiệu riêng. `dev_selftest`/`dev_selftest_at` cũng
196
- trực giao với `status` (OK/GAP/DRIFT/UNTRACKED): `status` theo dõi *coverage*, `dev_selftest`
197
+ trực giao với `status` (OK/GAP/DRIFT/UNTRACKED/ORPHANED): `status` theo dõi *coverage*, `dev_selftest`
197
198
  theo dõi *kết quả chạy* gần nhất của dev.
198
199
 
199
200
  ## Refresh Panel Mirror
@@ -34,23 +34,23 @@ Hiển thị và chờ phản hồi:
34
34
  ```
35
35
  ⚙️ MODEL CHECK
36
36
  ──────────────────────────────────────────────────────────────────
37
- Recommended : claude-opus-4 (hoặc model Opus mới nhất)
37
+ Recommended : model Opus mới nhất
38
38
  Why needed : Phân tích spec, review kiến trúc, sinh code đòi hỏi
39
- suy luận sâu. Model nhỏ hơn dễ bỏ sót edge case.
39
+ suy luận sâu. Model nhỏ hơn (Haiku/Sonnet) dễ bỏ sót edge case.
40
40
 
41
41
  Cách đổi trong Claude Code:
42
- SettingsModel chọn "claude-opus"
43
- • hoặc: /modelchọn claude-opus
42
+ /modelchọn model Opus
43
+ • hoặc: SettingsModel
44
44
 
45
- Đang chạy claude-opus?
46
- Y — đúng, đang dùng claude-opus → tiếp tục
45
+ Đang chạy một model Opus?
46
+ Y — đúng → tiếp tục
47
47
  S — bỏ qua kiểm tra (tôi chấp nhận rủi ro chất lượng thấp hơn với model hiện tại)
48
48
  ──────────────────────────────────────────────────────────────────
49
49
  ```
50
50
 
51
51
  - "Y" → tiếp tục sang Bước 1.
52
52
  - "S" → tiếp tục sang Bước 1 (người dùng chấp nhận rủi ro, thêm ⚠️ vào report cuối).
53
- - "N" hoặc bất kỳ giá trị nào khác → **DỪNG.** Xuất: "Vui lòng chuyển sang claude-opus rồi chạy lại lệnh này."
53
+ - "N" hoặc bất kỳ giá trị nào khác → **DỪNG.** Xuất: "Vui lòng chuyển sang một model Opus (`/model`) rồi chạy lại lệnh này."
54
54
 
55
55
  ## Bước 1 — Xác định Target File
56
56
 
@@ -59,7 +59,12 @@ Hiển thị và chờ phản hồi:
59
59
  2. Nếu `$ARGUMENTS` là một **UC-ID / ticket ID / tên rút gọn** (không có path) → phân giải thành file bằng cách glob theo bố cục feature-package. `{prd-slug}` lúc này **chưa biết**, nên dùng wildcard `*` cho segment đó, và `**` đệ quy dưới `bdd/` để phủ hết các thư mục con theo platform (`bdd/web/`, `bdd/app/`, `bdd/system/`):
60
60
  - **Lệnh BDD** (target là `.feature`): `{specs_dir}/{domain}/*/bdd/**/{UC-ID}*.feature` — hoặc `{specs_dir}/*/*/bdd/**/{UC-ID}*.feature` nếu domain cũng chưa biết. Nếu lệnh ngụ ý một platform/scope cụ thể (vd: system tech-doc cần BDD `system/`), ưu tiên kết quả trong thư mục con platform đó.
61
61
  - **Lệnh PRD** (target là file PRD `{TICKET-ID}-{prd-slug}.md` — file `.md` duy nhất ở gốc feature folder, cạnh `bdd/`): `{specs_dir}/{domain}/*/{TICKET-ID}*.md` nếu biết TICKET-ID; nếu không, `{specs_dir}/{domain}/*/*.md` (khớp feature folder có id tương ứng), hoặc `{specs_dir}/*/*/*.md` nếu domain cũng chưa biết. *(Glob `*/*.md` ở cấp gốc folder chỉ khớp PRD — tech-docs/design-spec `.md` nằm sâu hơn trong thư mục con.)*
62
- - **Lệnh tech-docs**: `{specs_dir}/{domain}/*/tech-docs/{UC-ID}*-tech-design*.md`.
62
+ - **Lệnh tech-docs** — target là tech-doc **gộp cấp PRD** `{TICKET-ID}-tech-design.md` (MỘT doc phủ nhiều UC; danh sách UC nằm ở `@trace.ucs`). Vì tên file mang `{TICKET-ID}` chứ **không** mang `{UC-ID}`, phải tách trước khi glob:
63
+ - `$ARGUMENTS` là **UC-ID** (`{TICKET-ID}-UC{N}`) → lấy `{TICKET-ID}` = phần **trước** `-UC`, rồi glob `{specs_dir}/{domain}/*/tech-docs/{TICKET-ID}-tech-design.md`.
64
+ - `$ARGUMENTS` là **TICKET-ID** → glob trực tiếp như trên.
65
+ - Chưa biết domain → `{specs_dir}/*/*/tech-docs/{TICKET-ID}-tech-design.md`.
66
+ - Vẫn không khớp → glob rộng `{specs_dir}/*/*/tech-docs/*tech-design*.md` rồi liệt kê để người dùng chọn.
67
+ *(Đừng glob `{UC-ID}*-tech-design*.md` — nó nở thành `FT-001-UC1*-tech-design*.md` và **không bao giờ** khớp `FT-001-tech-design.md`.)*
63
68
  - **Lệnh design-spec**: `{specs_dir}/{domain}/*/design-spec/{TICKET-ID}*.md`.
64
69
 
65
70
  Khi một file khớp: đặt nó làm target **và** ghi lại `domain` + `prd_slug` từ path của nó (theo quy tắc trích xuất trong `context-loader.md` Bước 1 — `prd_slug` = segment đầu tiên sau `{specs_dir}/{domain}/`). Mọi path mà lệnh đọc/ghi về sau (BDD/tech-docs/design-spec/trace cùng cấp) đều dùng **`prd_slug` đã phân giải đó**, nên tất cả artifact nằm chung một feature package. Nếu nhiều file khớp (vd: nhiều platform), chọn theo platform/scope của lệnh hoặc liệt kê ra và hỏi.
@@ -748,6 +753,7 @@ Gợi ý lệnh kế tiếp hợp lý theo phase của workflow:
748
753
  | /qc-run-test | `/qc-report {UC-ID}` rồi `/qc-review {UC-ID}` (review script) |
749
754
  | /qc-review (script) | `/qc-report {UC-ID}` rồi tạo PR nếu APPROVED |
750
755
  | /qc-report | `/validate-traces {UC-ID}` để làm mới Living Docs (qc_status) |
756
+ | /map-testids | `/qc-design-test {UC-ID}` (QC dựng Page Object từ contract §4.5.6 vừa ghi) |
751
757
  | /generate-tech-docs | `/review-tech-docs {tech-design-file}` |
752
758
  | /review-tech-docs | `/generate-code {feature-file}` nếu APPROVED; sửa doc nếu NEEDS_FIX |
753
759
  | /generate-code | Lần gen đầu → `/review-code {UC-ID}`; gen lại → `/dev-gen-test {UC-ID}` |
@@ -756,8 +762,8 @@ Gợi ý lệnh kế tiếp hợp lý theo phase của workflow:
756
762
  | /dev-run-test (failing) | `/fix-bug {ticket-id}` hoặc `/debug {error}` |
757
763
  | /review-code | `/dev-smoke-test {UC-ID}` hoặc tạo PR |
758
764
  | /dev-smoke-test | Tạo PR và link tới ticket |
759
- | /validate-traces | DRIFT/UNTRACKED → `/generate-code {UC-ID}`; GAP → `/dev-gen-test {UC-ID}`; tất cả OK tạo PR |
760
- | /fix-bug | Tạo PR link tới ticket |
765
+ | /validate-traces | **Cờ 🔴 trước (chặn PR):** SEAM_UNWIRED → nối binding sang class thật, xoá/thay stub · STUB_UNRESOLVED → `/generate-code {owner_uc}` (lấp logic tại chỗ + xoá hàm song song) · ORPHANED/TRACE_ORPHAN → quyết định thủ công (xoá code+test, đưa scenario trở lại `.feature`, hoặc sửa `sc_id` của tag). **Rồi:** DRIFT/UNTRACKED → `/generate-code {UC-ID}` · BDD_DRIFT → `/generate-code {feature-file}` · tech-doc lỗi thời vs BDD → `/generate-tech-docs` → `/review-tech-docs` · PRD drift → `/generate-bdd {prd-file}` · GAP → `/dev-gen-test {UC-ID}`. **Chỉ tạo PR khi mọi cờ 🔴 = 0** |
766
+ | /fix-bug | `/dev-run-test {UC-ID}` (dev_selftest vừa reset về not_run) → tạo PR; nếu fix một `{BUG-ID}` → QC chạy `/qc-run-test {UC-ID}` để verify + đóng bug |
761
767
  | /debug | `/fix-bug {ticket-id}` nếu cần sửa |
762
768
  | /report-bug | Gửi cho dev (`/fix-bug {BUG-ID}`); nếu thiếu coverage → `/propose-scenario {UC-ID}` |
763
769
  | /propose-scenario | Báo PO/Dev review proposal trong `feedback/bdd-proposals/` |
@@ -32,23 +32,23 @@ Hiển thị và chờ phản hồi:
32
32
  ```
33
33
  ⚙️ MODEL CHECK
34
34
  ──────────────────────────────────────────────────────────────────
35
- Recommended : claude-opus-4 (hoặc model Opus mới nhất)
35
+ Recommended : model Opus mới nhất
36
36
  Why needed : Phân tích spec, review kiến trúc, sinh code đòi hỏi
37
- suy luận sâu. Model nhỏ hơn dễ bỏ sót edge case.
37
+ suy luận sâu. Model nhỏ hơn (Haiku/Sonnet) dễ bỏ sót edge case.
38
38
 
39
39
  Cách đổi trong Claude Code:
40
- SettingsModel chọn "claude-opus"
41
- • hoặc: /modelchọn claude-opus
40
+ /modelchọn model Opus
41
+ • hoặc: SettingsModel
42
42
 
43
- Đang chạy claude-opus?
44
- Y — đúng, đang dùng claude-opus → tiếp tục
43
+ Đang chạy một model Opus?
44
+ Y — đúng → tiếp tục
45
45
  S — bỏ qua kiểm tra (tôi chấp nhận rủi ro chất lượng thấp hơn với model hiện tại)
46
46
  ──────────────────────────────────────────────────────────────────
47
47
  ```
48
48
 
49
49
  - "Y" → tiếp tục sang Bước 1.
50
50
  - "S" → tiếp tục sang Bước 1 (người dùng chấp nhận rủi ro, thêm ⚠️ vào report cuối).
51
- - "N" hoặc bất kỳ giá trị nào khác → **DỪNG.** Xuất: "Vui lòng chuyển sang claude-opus rồi chạy lại lệnh này."
51
+ - "N" hoặc bất kỳ giá trị nào khác → **DỪNG.** Xuất: "Vui lòng chuyển sang một model Opus (`/model`) rồi chạy lại lệnh này."
52
52
 
53
53
  ## Bước 1 — Xác định Target File
54
54
 
@@ -57,7 +57,12 @@ Hiển thị và chờ phản hồi:
57
57
  2. Nếu `$ARGUMENTS` là một **UC-ID / ticket ID / tên rút gọn** (không có path) → phân giải thành file bằng cách glob theo bố cục feature-package. `{prd-slug}` lúc này **chưa biết**, nên dùng wildcard `*` cho segment đó, và `**` đệ quy dưới `bdd/` để phủ hết các thư mục con theo platform (`bdd/web/`, `bdd/app/`, `bdd/system/`):
58
58
  - **Lệnh BDD** (target là `.feature`): `{specs_dir}/{domain}/*/bdd/**/{UC-ID}*.feature` — hoặc `{specs_dir}/*/*/bdd/**/{UC-ID}*.feature` nếu domain cũng chưa biết. Nếu lệnh ngụ ý một platform/scope cụ thể (vd: system tech-doc cần BDD `system/`), ưu tiên kết quả trong thư mục con platform đó.
59
59
  - **Lệnh PRD** (target là file PRD `{TICKET-ID}-{prd-slug}.md` — file `.md` duy nhất ở gốc feature folder, cạnh `bdd/`): `{specs_dir}/{domain}/*/{TICKET-ID}*.md` nếu biết TICKET-ID; nếu không, `{specs_dir}/{domain}/*/*.md` (khớp feature folder có id tương ứng), hoặc `{specs_dir}/*/*/*.md` nếu domain cũng chưa biết. *(Glob `*/*.md` ở cấp gốc folder chỉ khớp PRD — tech-docs/design-spec `.md` nằm sâu hơn trong thư mục con.)*
60
- - **Lệnh tech-docs**: `{specs_dir}/{domain}/*/tech-docs/{UC-ID}*-tech-design*.md`.
60
+ - **Lệnh tech-docs** — target là tech-doc **gộp cấp PRD** `{TICKET-ID}-tech-design.md` (MỘT doc phủ nhiều UC; danh sách UC nằm ở `@trace.ucs`). Vì tên file mang `{TICKET-ID}` chứ **không** mang `{UC-ID}`, phải tách trước khi glob:
61
+ - `$ARGUMENTS` là **UC-ID** (`{TICKET-ID}-UC{N}`) → lấy `{TICKET-ID}` = phần **trước** `-UC`, rồi glob `{specs_dir}/{domain}/*/tech-docs/{TICKET-ID}-tech-design.md`.
62
+ - `$ARGUMENTS` là **TICKET-ID** → glob trực tiếp như trên.
63
+ - Chưa biết domain → `{specs_dir}/*/*/tech-docs/{TICKET-ID}-tech-design.md`.
64
+ - Vẫn không khớp → glob rộng `{specs_dir}/*/*/tech-docs/*tech-design*.md` rồi liệt kê để người dùng chọn.
65
+ *(Đừng glob `{UC-ID}*-tech-design*.md` — nó nở thành `FT-001-UC1*-tech-design*.md` và **không bao giờ** khớp `FT-001-tech-design.md`.)*
61
66
  - **Lệnh design-spec**: `{specs_dir}/{domain}/*/design-spec/{TICKET-ID}*.md`.
62
67
 
63
68
  Khi một file khớp: đặt nó làm target **và** ghi lại `domain` + `prd_slug` từ path của nó (theo quy tắc trích xuất trong `context-loader.md` Bước 1 — `prd_slug` = segment đầu tiên sau `{specs_dir}/{domain}/`). Mọi path mà lệnh đọc/ghi về sau (BDD/tech-docs/design-spec/trace cùng cấp) đều dùng **`prd_slug` đã phân giải đó**, nên tất cả artifact nằm chung một feature package. Nếu nhiều file khớp (vd: nhiều platform), chọn theo platform/scope của lệnh hoặc liệt kê ra và hỏi.
@@ -569,9 +574,10 @@ git checkout -b fix/{TICKET_ID}-{description}
569
574
  ```
570
575
  Áp dụng fix. Thêm trace annotation nếu file có `@trace.implements`:
571
576
  ```
572
- @trace.fixes={TICKET_ID}
577
+ @trace.fixes={BUG-ID nếu fix từ một bug report đã file · else TICKET_ID}
573
578
  @trace.root_cause={brief description}
574
579
  ```
580
+ *(Ưu tiên `{BUG-ID}`: khi fix bắt nguồn từ `/report-bug` thì thường **không có** ticket ID nào, và `{BUG-ID}` mới là thứ trace ngược được về spec context + AC bị vi phạm.)*
575
581
 
576
582
  ## Phase 4 — Regression Test
577
583
  ```
@@ -581,7 +587,56 @@ Test: "Regression {TICKET_ID}: {bug description}"
581
587
  ```
582
588
  Chạy test. Nếu fail → debug và fix (tối đa 3 vòng).
583
589
 
584
- ## Phase 5 — Build & Commit (push 2 tầng ở umbrella mode)
590
+ ## Phase 4.5 — Cập nhật sổ trace
591
+
592
+ *Bỏ qua nếu fix không chạm SC nào có row trace (vd fix hạ tầng/config).*
593
+
594
+ Đây là lệnh **duy nhất** sinh test mà trước đây không ghi sổ — hệ quả: `test_count` under-report vĩnh viễn (SC đứng `GAP` dù vừa có regression test, rồi `/validate-traces` khuyên `/dev-gen-test` → dev sinh test trùng), và `dev_selftest` giữ `pass` cũ **trên code đã đổi**.
595
+
596
+ Định vị sổ platform `{paths.trace_dir}/{domain}/{prd-slug}/{UC-ID}-{platform}.tsv` — `{platform}` = platform của code vừa fix; không rõ → glob `{UC-ID}-*.tsv` tìm sổ nào chứa `sc_id` đó, khớp nhiều sổ → **hỏi** (cùng luật với `/report-bug` Step 5.5).
597
+
598
+ Với mỗi SC mà regression test phủ (theo `@trace.verifies` của test vừa viết):
599
+
600
+ | Cột | Giá trị |
601
+ |---|---|
602
+ | `test_count` | **+=** số test method regression vừa thêm (cộng dồn, không ghi đè) |
603
+ | `test_classes` | **append** tên test class/describe mới, giữ nguyên tên cũ |
604
+ | `dev_selftest` | `not_run` — code vừa đổi nên tín hiệu self-test cũ hết hiệu lực |
605
+ | `dev_selftest_at` | `—` |
606
+ | `last_updated` | hôm nay `YYYY-MM-DD` |
607
+
608
+ Giữ nguyên mọi cột khác. Đặc biệt:
609
+ - **KHÔNG** đụng `qc_status`/`qc_run_at`/`qc_owner`/`qc_blocked_by` — QC sở hữu; `/qc-run-test` sẽ flip khi re-verify (và chính nó đóng `{BUG-ID}` → `🟢 Closed`).
610
+ - **KHÔNG** đụng `spec_ver`/`gen_ver` — fix bug **không** đổi spec, nên không được tạo tín hiệu DRIFT giả.
611
+
612
+ Rồi làm mới panel mirror:
613
+ # Làm mới panel mirror của Living Docs *(local, chế độ umbrella)*
614
+
615
+ *Bỏ qua hoàn toàn ở chế độ single-service (không có `services` và không có `setup.spec_source`) — ở đó
616
+ `.trace/` của chính repo CHÍNH LÀ vị trí panel, nên không có gì để mirror.*
617
+
618
+ Sau khi cập nhật TSV authoritative tại `{paths.trace_dir}`:
619
+
620
+ **Khi `setup.spec_source` được đặt (trace gộp — trường hợp phổ biến):**
621
+ `{paths.trace_dir}` phân giải về `{spec_source}/.trace` — vị trí authoritative duy nhất.
622
+ Lệnh này chạy từ `service_root`, nên thao tác ghi là **liên-repo vào spec submodule**;
623
+ commit/push spec submodule cho lần cập nhật trace (giống như `feedback/`).
624
+ 1. Phân giải `panel_mirror = ./.trace` tại **gốc workspace hiện tại**.
625
+ 2. Nếu `panel_mirror` phân giải ra path khác với `{paths.trace_dir}`, copy mỗi
626
+ `{UC-ID}-{platform}.tsv` vừa cập nhật → `{panel_mirror}/{UC-ID}-{platform}.tsv` (tạo thư mục; ghi đè).
627
+ Không namespace theo service — chỉ có một bộ trace; service sở hữu được mang trong
628
+ `@trace.service` của từng row.
629
+
630
+ **Legacy (không có `spec_source` — trace theo service):**
631
+ Copy mỗi `{UC-ID}-{platform}.tsv` vừa cập nhật → `{panel_mirror}/{service-name}/{UC-ID}-{platform}.tsv`
632
+ (namespace theo `active_service`).
633
+
634
+ Cách này giữ panel Living Docs của workspace đang mở luôn mới **giữa các lần sync** — nó chỉ là
635
+ một **mirror tiện lợi cục bộ**. File `trace-report.json` đã merge (canonical, trong
636
+ `{spec_source}/.living-docs/`) được build lại bởi `/sync` hoặc `/validate-traces`. Với các lệnh
637
+ được orchestrate, làm việc này một lần trong orchestrator sau khi tất cả sub-agent trả về — không phải
638
+ bên trong từng sub-agent.
639
+
585
640
  ```bash
586
641
  {conventions.build_command} # tối đa 3 retry — chạy trong {service_root} ở umbrella mode
587
642
  # Tầng 1 — push fix branch trong service submodule (nơi code sống):
@@ -783,6 +838,7 @@ Gợi ý lệnh kế tiếp hợp lý theo phase của workflow:
783
838
  | /qc-run-test | `/qc-report {UC-ID}` rồi `/qc-review {UC-ID}` (review script) |
784
839
  | /qc-review (script) | `/qc-report {UC-ID}` rồi tạo PR nếu APPROVED |
785
840
  | /qc-report | `/validate-traces {UC-ID}` để làm mới Living Docs (qc_status) |
841
+ | /map-testids | `/qc-design-test {UC-ID}` (QC dựng Page Object từ contract §4.5.6 vừa ghi) |
786
842
  | /generate-tech-docs | `/review-tech-docs {tech-design-file}` |
787
843
  | /review-tech-docs | `/generate-code {feature-file}` nếu APPROVED; sửa doc nếu NEEDS_FIX |
788
844
  | /generate-code | Lần gen đầu → `/review-code {UC-ID}`; gen lại → `/dev-gen-test {UC-ID}` |
@@ -791,8 +847,8 @@ Gợi ý lệnh kế tiếp hợp lý theo phase của workflow:
791
847
  | /dev-run-test (failing) | `/fix-bug {ticket-id}` hoặc `/debug {error}` |
792
848
  | /review-code | `/dev-smoke-test {UC-ID}` hoặc tạo PR |
793
849
  | /dev-smoke-test | Tạo PR và link tới ticket |
794
- | /validate-traces | DRIFT/UNTRACKED → `/generate-code {UC-ID}`; GAP → `/dev-gen-test {UC-ID}`; tất cả OK tạo PR |
795
- | /fix-bug | Tạo PR link tới ticket |
850
+ | /validate-traces | **Cờ 🔴 trước (chặn PR):** SEAM_UNWIRED → nối binding sang class thật, xoá/thay stub · STUB_UNRESOLVED → `/generate-code {owner_uc}` (lấp logic tại chỗ + xoá hàm song song) · ORPHANED/TRACE_ORPHAN → quyết định thủ công (xoá code+test, đưa scenario trở lại `.feature`, hoặc sửa `sc_id` của tag). **Rồi:** DRIFT/UNTRACKED → `/generate-code {UC-ID}` · BDD_DRIFT → `/generate-code {feature-file}` · tech-doc lỗi thời vs BDD → `/generate-tech-docs` → `/review-tech-docs` · PRD drift → `/generate-bdd {prd-file}` · GAP → `/dev-gen-test {UC-ID}`. **Chỉ tạo PR khi mọi cờ 🔴 = 0** |
851
+ | /fix-bug | `/dev-run-test {UC-ID}` (dev_selftest vừa reset về not_run) → tạo PR; nếu fix một `{BUG-ID}` → QC chạy `/qc-run-test {UC-ID}` để verify + đóng bug |
796
852
  | /debug | `/fix-bug {ticket-id}` nếu cần sửa |
797
853
  | /report-bug | Gửi cho dev (`/fix-bug {BUG-ID}`); nếu thiếu coverage → `/propose-scenario {UC-ID}` |
798
854
  | /propose-scenario | Báo PO/Dev review proposal trong `feedback/bdd-proposals/` |
@@ -817,8 +873,10 @@ Next : {lệnh gợi ý kèm ví dụ tham số}
817
873
  Root Cause: {analysis}
818
874
  Changes: {list}
819
875
  ✅ Regression test added | ✅ Build: SUCCESS
876
+ {Trace: {UC-ID}-{platform}.tsv updated — test_count +{n}, dev_selftest → not_run | nếu có chạm row trace}
820
877
  {🐞 BUG-{id} → State: Fixed (pushed) — Closed sau khi /qc-run-test re-verify pass | nếu fix một bug đã file}
821
878
  {📝 Lesson L-NNN recorded (nếu đã capture)}
822
879
  Branch: fix/{TICKET_ID}-{slug}
823
- Next: Tạo PR và link tới ticket. {QC: chạy lại /qc-run-test {UC-ID} để verify + đóng bug | nếu áp dụng}
880
+ Next: /dev-run-test {UC-ID} dev_selftest vừa bị reset về not_run, chạy để lấy lại tín hiệu xanh
881
+ Rồi tạo PR và link tới ticket. {QC: chạy lại /qc-run-test {UC-ID} để verify + đóng bug | nếu áp dụng}
824
882
  ```
@@ -95,9 +95,10 @@ git checkout -b fix/{TICKET_ID}-{description}
95
95
  ```
96
96
  Áp dụng fix. Thêm trace annotation nếu file có `@trace.implements`:
97
97
  ```
98
- @trace.fixes={TICKET_ID}
98
+ @trace.fixes={BUG-ID nếu fix từ một bug report đã file · else TICKET_ID}
99
99
  @trace.root_cause={brief description}
100
100
  ```
101
+ *(Ưu tiên `{BUG-ID}`: khi fix bắt nguồn từ `/report-bug` thì thường **không có** ticket ID nào, và `{BUG-ID}` mới là thứ trace ngược được về spec context + AC bị vi phạm.)*
101
102
 
102
103
  ## Phase 4 — Regression Test
103
104
  ```
@@ -107,7 +108,30 @@ Test: "Regression {TICKET_ID}: {bug description}"
107
108
  ```
108
109
  Chạy test. Nếu fail → debug và fix (tối đa 3 vòng).
109
110
 
110
- ## Phase 5 — Build & Commit (push 2 tầng ở umbrella mode)
111
+ ## Phase 4.5 — Cập nhật sổ trace
112
+
113
+ *Bỏ qua nếu fix không chạm SC nào có row trace (vd fix hạ tầng/config).*
114
+
115
+ Đây là lệnh **duy nhất** sinh test mà trước đây không ghi sổ — hệ quả: `test_count` under-report vĩnh viễn (SC đứng `GAP` dù vừa có regression test, rồi `/validate-traces` khuyên `/dev-gen-test` → dev sinh test trùng), và `dev_selftest` giữ `pass` cũ **trên code đã đổi**.
116
+
117
+ Định vị sổ platform `{paths.trace_dir}/{domain}/{prd-slug}/{UC-ID}-{platform}.tsv` — `{platform}` = platform của code vừa fix; không rõ → glob `{UC-ID}-*.tsv` tìm sổ nào chứa `sc_id` đó, khớp nhiều sổ → **hỏi** (cùng luật với `/report-bug` Step 5.5).
118
+
119
+ Với mỗi SC mà regression test phủ (theo `@trace.verifies` của test vừa viết):
120
+
121
+ | Cột | Giá trị |
122
+ |---|---|
123
+ | `test_count` | **+=** số test method regression vừa thêm (cộng dồn, không ghi đè) |
124
+ | `test_classes` | **append** tên test class/describe mới, giữ nguyên tên cũ |
125
+ | `dev_selftest` | `not_run` — code vừa đổi nên tín hiệu self-test cũ hết hiệu lực |
126
+ | `dev_selftest_at` | `—` |
127
+ | `last_updated` | hôm nay `YYYY-MM-DD` |
128
+
129
+ Giữ nguyên mọi cột khác. Đặc biệt:
130
+ - **KHÔNG** đụng `qc_status`/`qc_run_at`/`qc_owner`/`qc_blocked_by` — QC sở hữu; `/qc-run-test` sẽ flip khi re-verify (và chính nó đóng `{BUG-ID}` → `🟢 Closed`).
131
+ - **KHÔNG** đụng `spec_ver`/`gen_ver` — fix bug **không** đổi spec, nên không được tạo tín hiệu DRIFT giả.
132
+
133
+ Rồi làm mới panel mirror:
134
+ {{include:steps/trace-mirror.md}}
111
135
  ```bash
112
136
  {conventions.build_command} # tối đa 3 retry — chạy trong {service_root} ở umbrella mode
113
137
  # Tầng 1 — push fix branch trong service submodule (nơi code sống):
@@ -164,8 +188,10 @@ Nếu `Y` → chạy quy trình capture bên dưới với `source=/fix-bug {TIC
164
188
  Root Cause: {analysis}
165
189
  Changes: {list}
166
190
  ✅ Regression test added | ✅ Build: SUCCESS
191
+ {Trace: {UC-ID}-{platform}.tsv updated — test_count +{n}, dev_selftest → not_run | nếu có chạm row trace}
167
192
  {🐞 BUG-{id} → State: Fixed (pushed) — Closed sau khi /qc-run-test re-verify pass | nếu fix một bug đã file}
168
193
  {📝 Lesson L-NNN recorded (nếu đã capture)}
169
194
  Branch: fix/{TICKET_ID}-{slug}
170
- Next: Tạo PR và link tới ticket. {QC: chạy lại /qc-run-test {UC-ID} để verify + đóng bug | nếu áp dụng}
195
+ Next: /dev-run-test {UC-ID} dev_selftest vừa bị reset về not_run, chạy để lấy lại tín hiệu xanh
196
+ Rồi tạo PR và link tới ticket. {QC: chạy lại /qc-run-test {UC-ID} để verify + đóng bug | nếu áp dụng}
171
197
  ```