@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.
- package/bin/build.js +9 -0
- package/bin/index.js +115 -4
- package/bin/self-check.js +236 -0
- package/bin/trace-schema.json +692 -0
- package/commands/debug.md +16 -10
- package/commands/define-product.md +16 -10
- package/commands/dev-gen-test.md +16 -10
- package/commands/dev-run-test.md +18 -11
- package/commands/dev-run-test.tmpl +2 -1
- package/commands/dev-smoke-test.md +16 -10
- package/commands/fix-bug.md +71 -13
- package/commands/fix-bug.tmpl +29 -3
- package/commands/generate-architecture.md +16 -10
- package/commands/generate-bdd.md +118 -35
- package/commands/generate-bdd.tmpl +89 -15
- package/commands/generate-code.md +49 -13
- package/commands/generate-code.tmpl +33 -3
- package/commands/generate-design-spec.md +16 -10
- package/commands/generate-prd.md +16 -10
- package/commands/generate-spec-manifest.md +16 -10
- package/commands/generate-tech-docs.md +19 -13
- package/commands/generate-tech-docs.tmpl +2 -2
- package/commands/learn.md +16 -10
- package/commands/map-testids.md +16 -10
- package/commands/propose-scenario.md +36 -12
- package/commands/propose-scenario.tmpl +20 -2
- package/commands/qc-analyze.md +16 -10
- package/commands/qc-design-test.md +16 -10
- package/commands/qc-plan.md +16 -10
- package/commands/qc-report.md +16 -10
- package/commands/qc-review.md +16 -10
- package/commands/qc-run-test.md +38 -12
- package/commands/qc-run-test.tmpl +22 -2
- package/commands/refine-prd.md +16 -10
- package/commands/report-bug.md +16 -10
- package/commands/review-code.md +56 -12
- package/commands/review-code.tmpl +40 -2
- package/commands/review-context.md +58 -14
- package/commands/review-context.tmpl +42 -4
- package/commands/review-tech-docs.md +47 -12
- package/commands/review-tech-docs.tmpl +31 -2
- package/commands/setup-ai-first.md +23 -14
- package/commands/setup-ai-first.tmpl +7 -4
- package/commands/sync.md +3 -2
- package/commands/update-framework.md +40 -2
- package/commands/update-framework.tmpl +37 -0
- package/commands/validate-traces.md +165 -18
- package/commands/validate-traces.tmpl +149 -8
- package/core/FRAMEWORK_VERSION +1 -1
- package/core/README.md +56 -0
- package/core/commands/debug.md +16 -10
- package/core/commands/define-product.md +16 -10
- package/core/commands/dev-gen-test.md +16 -10
- package/core/commands/dev-run-test.md +18 -11
- package/core/commands/dev-smoke-test.md +16 -10
- package/core/commands/fix-bug.md +71 -13
- package/core/commands/generate-architecture.md +16 -10
- package/core/commands/generate-bdd.md +118 -35
- package/core/commands/generate-code.md +49 -13
- package/core/commands/generate-design-spec.md +16 -10
- package/core/commands/generate-prd.md +16 -10
- package/core/commands/generate-spec-manifest.md +16 -10
- package/core/commands/generate-tech-docs.md +19 -13
- package/core/commands/learn.md +16 -10
- package/core/commands/map-testids.md +16 -10
- package/core/commands/propose-scenario.md +36 -12
- package/core/commands/qc-analyze.md +16 -10
- package/core/commands/qc-design-test.md +16 -10
- package/core/commands/qc-plan.md +16 -10
- package/core/commands/qc-report.md +16 -10
- package/core/commands/qc-review.md +16 -10
- package/core/commands/qc-run-test.md +38 -12
- package/core/commands/refine-prd.md +16 -10
- package/core/commands/report-bug.md +16 -10
- package/core/commands/review-code.md +56 -12
- package/core/commands/review-context.md +58 -14
- package/core/commands/review-tech-docs.md +47 -12
- package/core/commands/setup-ai-first.md +23 -14
- package/core/commands/sync.md +3 -2
- package/core/commands/update-framework.md +40 -2
- package/core/commands/validate-traces.md +165 -18
- package/core/modules/android-compose/stack-profile.yaml +1 -1
- package/core/modules/flutter/stack-profile.yaml +1 -1
- package/core/modules/ios-swiftui/stack-profile.yaml +1 -1
- package/core/modules/java-spring/stack-profile.yaml +1 -1
- package/core/modules/nextjs/stack-profile.yaml +1 -1
- package/core/modules/nuxt/stack-profile.yaml +1 -1
- package/core/modules/phaser-game/stack-profile.yaml +1 -1
- package/core/modules/php-laravel/stack-profile.yaml +1 -1
- package/core/modules/qc-playwright/stack-profile.yaml +1 -1
- package/core/modules/react/stack-profile.yaml +1 -1
- package/core/modules/react-native/stack-profile.yaml +1 -1
- package/core/modules/vue/stack-profile.yaml +1 -1
- package/core/rules/workflow.md +11 -0
- package/core/steps/gate.md +13 -8
- package/core/steps/report-footer.md +3 -2
- package/core/templates/README.md +47 -0
- package/core/templates/feature.template +13 -10
- package/core/templates/project-context.yaml +26 -14
- package/core/templates/tech-design.template.md +1 -1
- package/docs/02-concepts/traceability.md +29 -6
- package/docs/04-reference/trace-schema.md +128 -37
- package/modules/android-compose/stack-profile.yaml +1 -1
- package/modules/flutter/stack-profile.yaml +1 -1
- package/modules/ios-swiftui/stack-profile.yaml +1 -1
- package/modules/java-spring/stack-profile.yaml +1 -1
- package/modules/nextjs/stack-profile.yaml +1 -1
- package/modules/nuxt/stack-profile.yaml +1 -1
- package/modules/phaser-game/stack-profile.yaml +1 -1
- package/modules/php-laravel/stack-profile.yaml +1 -1
- package/modules/qc-playwright/stack-profile.yaml +1 -1
- package/modules/react/stack-profile.yaml +1 -1
- package/modules/react-native/stack-profile.yaml +1 -1
- package/modules/vue/stack-profile.yaml +1 -1
- package/package.json +50 -49
- package/rules/workflow.md +11 -0
- package/scripts/migrate-bdd-platform.js +286 -0
- package/steps/gate.md +13 -8
- package/steps/report-footer.md +3 -2
- package/templates/README.md +47 -0
- package/templates/feature.template +13 -10
- package/templates/project-context.yaml +26 -14
- package/templates/tech-design.template.md +1 -1
|
@@ -57,17 +57,38 @@ Nếu version SC trong `.feature` khác `spec_ver` của `.tsv` → cập nhật
|
|
|
57
57
|
|
|
58
58
|
Cũng phát hiện SC có trong `.feature` (platform đó) nhưng thiếu trong `.tsv` → thêm row mới với `status: UNTRACKED`. *(sc_id trùng số giữa các platform là 2 scenario khác nhau → mỗi sổ platform giữ tập SC riêng, không dedupe chéo platform.)*
|
|
59
59
|
|
|
60
|
+
### Step 2b — Reverse audit (bắt tag mồ côi)
|
|
61
|
+
|
|
62
|
+
*Step 2 đi chiều **spec → code** (mỗi row TSV, SC đó implement tới đâu). Step này đi **chiều ngược** — bắt lớp lỗi mà Step 2 cấu trúc không thể thấy: code trỏ vào một scenario **không còn tồn tại**. Xảy ra khi gen lại BDD làm một SC biến mất (gộp / đổi số / xoá) trong khi code implement nó vẫn nằm đó, vẫn được caller gọi.*
|
|
63
|
+
|
|
64
|
+
**Quét (gộp vào cùng lượt quét code của Step 5b — không thêm pass mới):** dưới `{code_base_package}` (CLAUDE.md §2) + `{paths.src_dir}`, thu mọi `@trace.implements={UC-ID}-SC{N}`; trong thư mục test thu mọi `@trace.verifies={UC-ID}-SC{N}`.
|
|
65
|
+
|
|
66
|
+
Với mỗi tag, hỏi: `SC{N}` đó có tồn tại trong `.feature` của đúng platform không?
|
|
67
|
+
|
|
68
|
+
| Điều kiện | Cờ | Ý nghĩa |
|
|
69
|
+
|---|---|---|
|
|
70
|
+
| SC không có trong `.feature`, **và** row TSV còn (đã mang `status = ORPHANED` do `/generate-bdd` giữ lại) | `ORPHANED` 🔴 | Đã được ghi nhận — đang chờ người quyết định |
|
|
71
|
+
| SC không có trong `.feature`, **và** không có row TSV nào | `TRACE_ORPHAN` 🔴 | Nợ cũ: row bị xoá bởi version trước, hoặc tag ghi sai UC/SC id ngay từ đầu. **Không có chỗ nào khác bắt được cái này.** |
|
|
72
|
+
| SC có trong `.feature` | *(sạch)* | |
|
|
73
|
+
|
|
74
|
+
**Với `TRACE_ORPHAN`:** đừng tự tạo row TSV (chưa biết nó nên là scenario nào) và **đừng** sửa/xoá code. Chỉ report kèm đúng hai đường ra ở §Output.
|
|
75
|
+
|
|
76
|
+
Không tìm thấy tag mồ côi nào → bỏ qua im lặng.
|
|
77
|
+
|
|
60
78
|
### Step 3 — Tính `status` theo từng scenario
|
|
61
79
|
|
|
62
80
|
Áp dụng quy tắc theo thứ tự ưu tiên (first-match-wins):
|
|
63
81
|
|
|
64
82
|
| Rule | Status | Điều kiện |
|
|
65
83
|
|------|--------|-----------|
|
|
84
|
+
| 0 | `ORPHANED` | SC của row này **không còn trong `.feature`** (Step 2b) AND `implemented_by != —` — code trỏ vào scenario đã bị xoá |
|
|
66
85
|
| 1 | `UNTRACKED` | `implemented_by == —` (chưa sinh code) |
|
|
67
86
|
| 2 | `DRIFT` | `implemented_by != —` AND `spec_ver != gen_ver` (spec đã đổi sau lần codegen — code cũ, **ưu tiên regen trước khi test**) |
|
|
68
87
|
| 3 | `GAP` | `implemented_by != —` AND (`test_count == —` OR `test_count == 0`) |
|
|
69
88
|
| 4 | `OK` | tất cả: `spec_ver == gen_ver`, `implemented_by != —`, `test_count > 0` |
|
|
70
89
|
|
|
90
|
+
> **Vì sao ORPHANED là Rule 0 (xét TRƯỚC mọi rule khác):** 4 rule kia đều giả định scenario **còn tồn tại** — chúng trả lời "spec này implement tới đâu". `ORPHANED` trả lời câu ngược: "code này còn spec nào bảo lãnh không". Nếu để rule khác thắng, mỗi giá trị đều **route người dùng sang một lệnh vô nghĩa**: `GAP` → `/dev-gen-test` sinh test cho scenario không tồn tại · `DRIFT` → `/generate-code` cố sinh lại từ SC đã bị xoá · `OK` → coi là sạch và cho tạo PR. Row cũng KHÔNG được xoá — xoá đi thì code thành vô hình (chính là bug gốc).
|
|
91
|
+
|
|
71
92
|
> **Vì sao DRIFT xét trước GAP:** một scenario đã có code, chưa test, **và** spec vừa drift phải hiện `DRIFT` (không phải `GAP`) — vì `generate-code` xử `GAP` = "skip codegen, chạy /dev-gen-test" còn `DRIFT` = "regenerate". Nếu GAP thắng, code lỗi thời bị bỏ qua và test lại sinh trên code cũ. UNTRACKED vẫn phải là Rule 1 để scenario chưa code (gen_ver `—`) không lọt vào DRIFT.
|
|
72
93
|
|
|
73
94
|
### Step 4 — PRD version drift check
|
|
@@ -90,6 +111,26 @@ Mỗi PRD có **một** tech-doc gộp `{paths.tech_docs_dir}/{domain}/{prd-slug
|
|
|
90
111
|
|
|
91
112
|
Skip cột nào chưa có revision đã lưu (`—`), hoặc cả UC chưa có tech-doc.
|
|
92
113
|
|
|
114
|
+
### Step 5c — BDD version drift check
|
|
115
|
+
|
|
116
|
+
*Đối xứng với Step 4 (PRD drift). Trước đây tầng BDD là tầng DUY NHẤT không có cờ drift — dù `/generate-code` vẫn ghi `@trace.bdd_version` vào code và JSON report vẫn lưu nó. Dữ liệu có, chỉ thiếu phép so.*
|
|
117
|
+
|
|
118
|
+
**Chiều BDD → code.** Với mỗi UC × platform, so:
|
|
119
|
+
- `@trace.bdd_version` **hiện tại** của `.feature` (`bdd/{platform}/{UC-ID}*.feature`)
|
|
120
|
+
- `@trace.bdd_version` trong các file code implement UC đó
|
|
121
|
+
|
|
122
|
+
Code mang version cũ hơn → gắn cờ `BDD_DRIFT`. Kèm theo, liệt kê các SC của UC đó đang `DRIFT` (từ Step 3) để chỉ đúng chỗ cần regen — `bdd_version` nói "file đã đổi", `sc_version` nói "đổi ở SC nào".
|
|
123
|
+
|
|
124
|
+
> **Bổ trợ, không thay thế `sc_version`:** `sc_version` bắt thay đổi trong **thân scenario**. `bdd_version` bắt thay đổi ở **cấp file** mà `sc_version` không thấy: `Background`, `@trace.dataset`, khối BUSINESS DEFINITION, Popup/Modal Lifecycle, Display Logic Matrix, Coverage Matrix. Code sinh ra phụ thuộc cả hai.
|
|
125
|
+
|
|
126
|
+
**File code KHÔNG có tag `@trace.bdd_version`** (code sinh trước khi tag này bắt buộc) → không kết luận drift được. Đếm và in **một dòng** tổng hợp:
|
|
127
|
+
```
|
|
128
|
+
⚠️ {n} file thiếu tag @trace.bdd_version → drift detection mù ở các file này.
|
|
129
|
+
Bổ sung tag khi sửa file lần tới (/review-code lăng kính Traceability sẽ bắt).
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
**Chiều BDD → tech-doc** *(chỉ report, cổng chặn nằm ở `/review-tech-docs`)*: đọc map `@trace.bdd_versions` của tech-doc gộp; platform nào có `.feature` **mới hơn** entry trong map → gắn cờ `TECHDOC_STALE_VS_BDD`. Đây là ca nguy hiểm hơn drift-về-code: `/generate-code` DS3 thấy tech-doc `approved` sẽ lấy shape §4 **nguyên văn** làm contract "đã chốt", nên contract dựng từ BDD cũ sẽ lan thẳng vào code.
|
|
133
|
+
|
|
93
134
|
### Step 5b — Seam & Stub Audit (mồ côi khi ghép luồng)
|
|
94
135
|
|
|
95
136
|
*Bắt lỗi "gen từng BDD thì đúng, ghép cả luồng thì hỏng": chỗ giả lập còn rỗng trong khi hàng thật đã tồn tại ở nơi khác — luồng chạy vào no-op / hàm thật không ai gọi. Build vẫn xanh, test từng-UC vẫn xanh, nên không cổng nào khác bắt được. Hai loại: `seam` (port cross-UC chưa nối) và `stub` (method trắng nội-feature chưa lấp).*
|
|
@@ -134,6 +175,7 @@ Không tìm thấy seam/stub nào → bỏ qua im lặng.
|
|
|
134
175
|
|
|
135
176
|
Với mỗi file `.tsv` đã xử lý: ghi `spec_ver`, `status`, `last_updated` đã cập nhật lại disk.
|
|
136
177
|
Đồng thời **đồng bộ `uc_status` ← `@trace.status`** của file `.feature` tương ứng (header `.feature` là nguồn-sự-thật về duyệt BDD — người đặt `approved` sau khi review sạch, giống PO đặt PRD Metadata `Status`). Nhờ vậy `approved_ucs` trên dashboard phản ánh đúng thay vì luôn = 0.
|
|
178
|
+
Và **đồng bộ `prd_status` ← `| **Status** |`** của PRD tương ứng (`{paths.specs_dir}/{domain}/{prd-slug}/{TICKET-ID}-{prd-slug}.md`) — đối xứng với `uc_status`: PRD Metadata là nguồn-sự-thật về duyệt PRD. Không có bước này thì `prd_status` là **write-once** (chỉ `/generate-bdd` ghi một lần) và sẽ giữ `approved` vĩnh viễn sau khi `/refine-prd` hay `/review-context --fix` reset PRD về `draft`. *(Step 4 đã đọc file PRD này rồi — không phát sinh I/O.)*
|
|
137
179
|
**Đừng** sửa `dev_selftest`/`dev_selftest_at` (do `/dev-run-test` sở hữu) hay `qc_status`/`qc_run_at`/`qc_owner`/`qc_blocked_by` (do `/qc-run-test` + `/report-bug` sở hữu); lệnh này chỉ đọc chúng cho report.
|
|
138
180
|
|
|
139
181
|
### Step 7 — Tính aggregate cho dashboard
|
|
@@ -144,12 +186,24 @@ approved_prds = PRDs with | Status | approved
|
|
|
144
186
|
total_ucs = count distinct UC-IDs across all .tsv files (strip the -{platform} suffix from the filename)
|
|
145
187
|
approved_ucs = UCs with uc_status == approved
|
|
146
188
|
draft_ucs = UCs with uc_status == draft
|
|
147
|
-
total_scs =
|
|
189
|
+
total_scs = rows across all .tsv files WHERE status != ORPHANED
|
|
190
|
+
# (a UC's SCs are counted per platform — no cross-platform dedupe by sc_id)
|
|
191
|
+
# ORPHANED bị LOẠI khỏi mẫu số: nó không còn là scope nữa (scenario đã bị xoá
|
|
192
|
+
# khỏi .feature). Tính vào mẫu số sẽ bóp méo coverage theo hướng xấu đi vì một
|
|
193
|
+
# thứ không ai cần implement. Nó được đếm riêng ở orphaned_count + cờ 🔴.
|
|
148
194
|
code_coverage = rows where implemented_by != — / total_scs
|
|
149
195
|
test_coverage = rows where test_count > 0 / total_scs
|
|
150
196
|
drift_count = rows where status == DRIFT
|
|
151
197
|
untracked_count = rows where status == UNTRACKED
|
|
152
198
|
gap_count = rows where status == GAP
|
|
199
|
+
fe_on_mock = rows where fe_phase == ui # FE đã có UI nhưng CÒN DÙNG MOCK — chưa wire API thật
|
|
200
|
+
fe_integrated = rows where fe_phase == integrated # FE đã wire adapter thật theo tech-doc §4.5.4
|
|
201
|
+
# fe_phase trả lời câu của PM: "màn nào demo được nhưng chưa nối backend?". Row `ui` là
|
|
202
|
+
# công việc CHƯA XONG dù status có thể đã là OK (có code + có test trên mock).
|
|
203
|
+
orphaned_count = rows where status == ORPHANED # code còn, scenario đã bị xoá khỏi .feature (Step 2b/Rule 0)
|
|
204
|
+
trace_orphan_count = số tag @trace.implements/@trace.verifies trỏ vào SC không tồn tại VÀ không có row TSV (Step 2b)
|
|
205
|
+
bdd_drift_count = số UC×platform bị cờ BDD_DRIFT (code mang @trace.bdd_version cũ hơn .feature — Step 5c)
|
|
206
|
+
techdoc_stale_vs_bdd_count = số platform mà tech-doc dựng từ bdd_version cũ hơn .feature hiện tại (Step 5c)
|
|
153
207
|
seam_unwired_count = số seam bị cờ SEAM_UNWIRED (hàng thật đã có nhưng consumer còn wire vào stub — Step 5b)
|
|
154
208
|
stub_unresolved_count = số stub bị cờ STUB_UNRESOLVED (method còn trắng dù owner đã gen / có hàm song song — Step 5b)
|
|
155
209
|
dev_selftest_passing = rows where dev_selftest == pass
|
|
@@ -193,6 +247,12 @@ Schema:
|
|
|
193
247
|
"drift_count": 0,
|
|
194
248
|
"gap_count": 0,
|
|
195
249
|
"untracked_count": 0,
|
|
250
|
+
"fe_on_mock": 0,
|
|
251
|
+
"fe_integrated": 0,
|
|
252
|
+
"orphaned_count": 0,
|
|
253
|
+
"trace_orphan_count": 0,
|
|
254
|
+
"bdd_drift_count": 0,
|
|
255
|
+
"techdoc_stale_vs_bdd_count": 0,
|
|
196
256
|
"seam_unwired_count": 0,
|
|
197
257
|
"stub_unresolved_count": 0,
|
|
198
258
|
"dev_selftest_passing": 0,
|
|
@@ -240,6 +300,7 @@ Schema:
|
|
|
240
300
|
"tech_doc_revision": 0,
|
|
241
301
|
"fe_tech_doc_revision": 0,
|
|
242
302
|
"status": "OK | DRIFT | GAP | UNTRACKED",
|
|
303
|
+
"orphaned": false,
|
|
243
304
|
"last_updated": "<YYYY-MM-DD>"
|
|
244
305
|
}
|
|
245
306
|
]
|
|
@@ -281,6 +342,42 @@ Schema:
|
|
|
281
342
|
"fix": "/generate-bdd <prd-file> then /generate-code <UC-ID>"
|
|
282
343
|
}
|
|
283
344
|
],
|
|
345
|
+
"bdd_drift": [
|
|
346
|
+
{
|
|
347
|
+
"uc_id": "<UC-ID>",
|
|
348
|
+
"platform": "web | app | system",
|
|
349
|
+
"code_bdd_version": "<@trace.bdd_version trong code>",
|
|
350
|
+
"current_bdd_version": "<@trace.bdd_version của .feature>",
|
|
351
|
+
"drifted_scs": ["<SC đang DRIFT của UC này>"],
|
|
352
|
+
"fix": "/generate-code <feature-file>"
|
|
353
|
+
}
|
|
354
|
+
],
|
|
355
|
+
"techdoc_stale_vs_bdd": [
|
|
356
|
+
{
|
|
357
|
+
"uc_id": "<UC-ID>",
|
|
358
|
+
"platform": "web | app | system",
|
|
359
|
+
"techdoc_bdd_version": "<entry trong map @trace.bdd_version của tech-doc>",
|
|
360
|
+
"current_bdd_version": "<@trace.bdd_version của .feature>",
|
|
361
|
+
"fix": "/generate-tech-docs <feature-file> then /review-tech-docs"
|
|
362
|
+
}
|
|
363
|
+
],
|
|
364
|
+
"orphaned": [
|
|
365
|
+
{
|
|
366
|
+
"sc_id": "<SC-ID đã bị xoá khỏi .feature>",
|
|
367
|
+
"platform": "web | app | system",
|
|
368
|
+
"implemented_by": "<ClassName.method còn tồn tại>",
|
|
369
|
+
"test_classes": ["<test còn trỏ vào SC này>"],
|
|
370
|
+
"fix": "xoá code + test, HOẶC đưa scenario trở lại .feature"
|
|
371
|
+
}
|
|
372
|
+
],
|
|
373
|
+
"trace_orphan": [
|
|
374
|
+
{
|
|
375
|
+
"tag": "@trace.implements | @trace.verifies",
|
|
376
|
+
"sc_id": "<SC-ID không tồn tại>",
|
|
377
|
+
"file": "<file mang tag>",
|
|
378
|
+
"fix": "sửa sc_id cho đúng SC hiện có, HOẶC xoá code/test nếu không còn cần"
|
|
379
|
+
}
|
|
380
|
+
],
|
|
284
381
|
"techdoc_drift": [
|
|
285
382
|
{
|
|
286
383
|
"uc_id": "<UC-ID>",
|
|
@@ -328,6 +425,10 @@ Schema:
|
|
|
328
425
|
- `test_classes`: dùng `[]` (không phải `"—"`) khi không có test class
|
|
329
426
|
- `tech_doc_revision` / `fe_tech_doc_revision`: dùng integer; `0` nếu chưa sinh
|
|
330
427
|
- `code_coverage_pct` / `test_coverage_pct`: làm tròn về integer gần nhất (0–100)
|
|
428
|
+
- **`status` trong JSON CỐ TÌNH chỉ có 4 giá trị** `OK`/`DRIFT`/`GAP`/`UNTRACKED` — KHÔNG ghi `ORPHANED` vào field này. VS Code extension "Spec Driven Docs Tools" (sống **ngoài** repo này) switch trên `status`; thêm giá trị thứ 5 sẽ rơi vào nhánh không khớp và có thể làm row mất khỏi panel.
|
|
429
|
+
Row `ORPHANED` xuất ra JSON là: `"status": "DRIFT"` + `"orphaned": true`. Panel chưa hỗ trợ vẫn hiện nó như `DRIFT` — đủ đúng về nghĩa ("code không khớp spec, cần xử lý") và **không im lặng**; panel có đọc `orphaned` thì hiện nhãn riêng. Chi tiết đầy đủ luôn có ở `orphaned[]` và ở report terminal.
|
|
430
|
+
**TSV giữ nguyên chữ `ORPHANED`** trong cột `status` — TSV là nguồn-sự-thật, JSON chỉ là bản xuất cho panel.
|
|
431
|
+
- `orphaned` (boolean): `true` chỉ khi cột `status` của TSV là `ORPHANED`; mọi row khác ghi `false` (đừng bỏ trống — panel đọc field vắng dễ ra `undefined`).
|
|
331
432
|
- Luôn ghi vào `{paths.trace_dir}/trace-report.json` bất kể domain filter — nếu có domain filter, chỉ gồm các PRD đó trong `prds[]` nhưng ghi domain vào field `domain`
|
|
332
433
|
- **TSV `"—"` mapping**: khi đọc file TSV, map giá trị dash sang kiểu JSON: `implemented_by: "—"` → `null`; `test_count: "—"` → `0`; `test_classes: "—"` → `[]`; `tech_doc_revision: "—"` → `0`; `fe_tech_doc_revision: "—"` → `0`; `dev_selftest: "—"` → `"not_run"`; `dev_selftest_at: "—"` → `null`; `qc_status: "—"` → `"not_run"`; `qc_run_at: "—"` → `null`; `qc_owner: "—"` → `null`; `qc_blocked_by: "—"` → `null`
|
|
333
434
|
- **Backward-compat:** TSV cũ có thể thiếu cột mới hơn trong header — coi cột vắng nào là giá trị rỗng của nó (đừng báo lỗi): `qc_owner`/`qc_blocked_by` (pre-19-col) → `null`; `fe_tech_doc_revision` (pre-22-col) → `0`. Lần `/generate-bdd` gen lại tiếp theo nâng header lên layout 22 cột hiện tại.
|
|
@@ -377,10 +478,11 @@ mỗi scenario row mang service sở hữu qua `@trace.service`. Step này chỉ
|
|
|
377
478
|
│ {N} {N} {N} {N}% {N}% {N} {N} {N} │
|
|
378
479
|
│ {A} appr {A} appr {X}/{T} SCs {X}/{T} SCs │
|
|
379
480
|
└─────────────────────────────────────────────────────────────────────────────────────┘
|
|
380
|
-
{nếu
|
|
381
|
-
🔴 GATE —
|
|
382
|
-
|
|
383
|
-
|
|
481
|
+
{in dòng GATE nếu BẤT KỲ cờ 🔴 nào > 0 (seam_unwired · stub_unresolved · orphaned · trace_orphan) — ngược lại bỏ cả khối}
|
|
482
|
+
🔴 GATE — có MỒ CÔI: {seam_unwired_count} SEAM_UNWIRED · {stub_unresolved_count} STUB_UNRESOLVED
|
|
483
|
+
· {orphaned_count} ORPHANED · {trace_orphan_count} TRACE_ORPHAN
|
|
484
|
+
Build xanh, test từng-UC xanh, coverage đẹp — nhưng luồng ghép chạy vào no-op,
|
|
485
|
+
hoặc code đang trỏ vào scenario đã bị xoá. KHÔNG coi là pass tới khi CẢ BỐN = 0.
|
|
384
486
|
|
|
385
487
|
| UC-ID | SC | Title (truncated) | Spec | Gen | Code | Tests | Status |
|
|
386
488
|
|-------------|------|------------------------------|-------|-------|----------------------|----------------|----------|
|
|
@@ -388,11 +490,43 @@ mỗi scenario row mang service sở hữu qua `@trace.service`. Step này chỉ
|
|
|
388
490
|
| {UC}-UC1 | SC2 | {title...} | v1.1 | v1.0 | ✅ {Controller.fn} | ✅ 3 tests | DRIFT |
|
|
389
491
|
| {UC}-UC1 | SC6 | {title...} | v1.0 | — | — | — | UNTRACKED|
|
|
390
492
|
| {UC}-UC2 | SC1 | {title...} | v1.0 | v1.0 | ✅ {Controller.fn} | — | GAP |
|
|
493
|
+
| {UC}-UC2 | SC7 | {title...} ⚠ đã xoá khỏi spec| — | v1.0 | ✅ {Controller.fn} | ✅ 2 tests | ORPHANED |
|
|
391
494
|
|
|
392
495
|
Drift Detail:
|
|
393
496
|
{UC}-UC1-SC2 — spec v1.1 nhưng code sinh từ v1.0
|
|
394
497
|
→ Chạy lại: /generate-code {UC-ID}
|
|
395
498
|
|
|
499
|
+
BDD Version Drift (file .feature đổi ở cấp file — Background/dataset/business definition):
|
|
500
|
+
{UC}-UC1 (web) — code sinh từ BDD v1.4, .feature giờ v1.6 [SC đang DRIFT: SC2, SC5]
|
|
501
|
+
→ /generate-code {feature-file}
|
|
502
|
+
⚠️ {n} file code thiếu tag @trace.bdd_version → drift detection mù ở các file này
|
|
503
|
+
|
|
504
|
+
Tech-doc lỗi thời so với BDD:
|
|
505
|
+
{UC}-UC3 (system) — tech-doc dựng từ BDD v1.5, .feature giờ v2.0
|
|
506
|
+
⚠️ Nguy hiểm hơn drift-về-code: DS3 của /generate-code coi §4 approved là contract
|
|
507
|
+
"đã chốt" và lấy shape NGUYÊN VĂN → contract từ BDD cũ lan thẳng vào code.
|
|
508
|
+
→ /generate-tech-docs {feature-file} → /review-tech-docs (cổng T-BDD)
|
|
509
|
+
|
|
510
|
+
FE còn dùng mock (fe_phase = ui — có UI + test nhưng CHƯA nối API thật):
|
|
511
|
+
{UC}-UC1 (web) — {n} SC ở fe_phase=ui
|
|
512
|
+
→ /generate-code {feature-file} --phase=integration (hoặc để trống --phase cho fe_full)
|
|
513
|
+
⚠️ Các SC này có thể đang hiện OK: có code, có test — nhưng test chạy trên mock.
|
|
514
|
+
Đừng coi là xong tính năng.
|
|
515
|
+
|
|
516
|
+
Orphaned (scenario đã bị xoá khỏi .feature nhưng code còn):
|
|
517
|
+
{UC}-UC2-SC7 (web) — "{sc_title}"
|
|
518
|
+
Code : {ControllerClass}.{method}
|
|
519
|
+
Test : {TestClass} (2 tests)
|
|
520
|
+
Không tự hết — chọn MỘT:
|
|
521
|
+
(a) code không còn cần → xoá method + test, rồi xoá row khỏi .tsv
|
|
522
|
+
(b) SC bị xoá do nhầm → đưa scenario trở lại .feature → row về DRIFT/OK bình thường
|
|
523
|
+
|
|
524
|
+
Trace orphan (tag trỏ vào SC không tồn tại, KHÔNG có row .tsv nào):
|
|
525
|
+
{file}:{line} — @trace.implements={UC}-UC1-SC9 nhưng .feature chỉ có tới SC5
|
|
526
|
+
→ Sửa sc_id cho đúng SC hiện có, HOẶC xoá code/test nếu không còn cần
|
|
527
|
+
(Không lệnh nào khác bắt được cái này — row .tsv đã bị xoá bởi version cũ,
|
|
528
|
+
hoặc tag ghi sai id ngay từ đầu.)
|
|
529
|
+
|
|
396
530
|
PRD Version Drift:
|
|
397
531
|
{UC}-UC2 — code ở PRD v1.0, PRD giờ ở v1.2
|
|
398
532
|
Thay đổi kể từ v1.0:
|
|
@@ -415,11 +549,18 @@ Seam & Stub Audit (mồ côi khi ghép luồng):
|
|
|
415
549
|
ⓘ STUB_PENDING — {ClassName#method} ({stub_for}): owner {owner_uc} chưa gen (chưa phải lỗi)
|
|
416
550
|
|
|
417
551
|
Recommendations:
|
|
418
|
-
- /generate-code {UC-ID}
|
|
419
|
-
- /dev-gen-test {UC-ID}
|
|
420
|
-
- /generate-bdd {prd-file}
|
|
552
|
+
- /generate-code {UC-ID} cho scenario DRIFT và UNTRACKED
|
|
553
|
+
- /dev-gen-test {UC-ID} cho GAP (thiếu test)
|
|
554
|
+
- /generate-bdd {prd-file} cho PRD version drift
|
|
555
|
+
- /generate-code {feature-file} cho BDD_DRIFT (code sinh từ .feature cũ hơn)
|
|
556
|
+
- /generate-tech-docs + /review-tech-docs cho tech-doc lỗi thời so với BDD
|
|
421
557
|
- Nối binding thủ công cho mỗi SEAM_UNWIRED 🔴 (hàng thật đã có, còn kẹt stub)
|
|
422
558
|
- /generate-code {owner_uc} cho mỗi STUB_UNRESOLVED 🔴 (lấp method trắng tại chỗ + xoá hàm song song)
|
|
559
|
+
- Quyết định thủ công cho mỗi ORPHANED / TRACE_ORPHAN 🔴 — xoá code+test, hoặc đưa
|
|
560
|
+
scenario trở lại .feature, hoặc sửa sc_id của tag.
|
|
561
|
+
KHÔNG có lệnh tự xử: cần người xác nhận behavior còn cần hay không.
|
|
562
|
+
|
|
563
|
+
⚠️ Chỉ tạo PR khi mọi cờ 🔴 = 0 (SEAM_UNWIRED · STUB_UNRESOLVED · ORPHANED · TRACE_ORPHAN).
|
|
423
564
|
|
|
424
565
|
[Chỉ umbrella mode]
|
|
425
566
|
Living Docs canonical → {living_docs_dir}/ (specs module — shared, gitignored)
|
package/core/FRAMEWORK_VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
0.4.
|
|
1
|
+
0.4.2
|
package/core/README.md
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
<!--
|
|
2
|
+
File này là nguồn của .agent/README.md: build.js copy AGENT_README.md (gốc repo
|
|
3
|
+
framework) → core/README.md, rồi `--init` cài thành .agent/README.md.
|
|
4
|
+
Muốn sửa nội dung: sửa AGENT_README.md TRONG REPO FRAMEWORK rồi `npm run build`.
|
|
5
|
+
Bản nằm trong .agent/ bị ghi đè mỗi lần nâng cấp — chính là điều nó đang nói.
|
|
6
|
+
-->
|
|
7
|
+
|
|
8
|
+
# `.agent/` — framework files (SINH RA, đừng sửa)
|
|
9
|
+
|
|
10
|
+
> Thư mục này do SDD Framework cài vào. `/update-framework` (thực chất là `npx @educa-corp/sdd-framework --init`) **copy `core/` → `.agent/` vô điều kiện** mỗi lần nâng cấp.
|
|
11
|
+
|
|
12
|
+
## Sửa được cái gì
|
|
13
|
+
|
|
14
|
+
| Đường dẫn | Sửa được? | Ghi chú |
|
|
15
|
+
|---|:---:|---|
|
|
16
|
+
| `.agent/project-context.yaml` | ✅ **Có** | **Đây là file cấu hình của bạn.** Được bảo vệ: `--init` chỉ tạo nếu chưa tồn tại, không bao giờ ghi đè. |
|
|
17
|
+
| `.agent/project-lessons.md` | ✅ Có | Do `/learn` quản lý. Không nằm trong `core/` nên nâng cấp không đụng tới. |
|
|
18
|
+
| `.agent/review/` | ✅ Có | File findings của `/review-context`, `/refine-prd`, `/review-tech-docs`. Không nằm trong `core/`. |
|
|
19
|
+
| `.agent/commands/` | ❌ Không | Sinh từ `commands/*.tmpl` của repo framework |
|
|
20
|
+
| `.agent/steps/` `rules/` `skills/` `hooks/` | ❌ Không | Copy từ repo framework |
|
|
21
|
+
| `.agent/templates/` | ❌ Không | **Cả bản tham khảo cũng không được đọc lúc chạy** — skeleton đã nướng cứng vào `.agent/commands/*.md` lúc build. Xem `.agent/templates/README.md`. |
|
|
22
|
+
| `.agent/modules/{module}/` | ❌ Không | Stack profile — đây là chỗ hay bị sửa nhất, và cũng là chỗ mất nhiều nhất khi nâng cấp |
|
|
23
|
+
|
|
24
|
+
## Nếu bạn đã sửa gì trong vùng ❌
|
|
25
|
+
|
|
26
|
+
Từ v0.4.2, `--init` **phát hiện và cứu** các file đó:
|
|
27
|
+
|
|
28
|
+
- Bản cũ được copy sang `.agent/.overwritten-{version}-{YYYYMMDD}/` giữ nguyên cây thư mục
|
|
29
|
+
- Danh sách file bị ghi đè được in ra ngay sau bước cài
|
|
30
|
+
- `.agent/.install-manifest.json` ghi hash của đúng những gì lần cài trước đã ghi — nhờ đó lệnh phân biệt được **bạn sửa file** với **framework tự đổi file giữa hai version** (một phép so nội dung thuần sẽ flag cả hai, và mỗi lần nâng cấp lại báo oan hàng chục file)
|
|
31
|
+
|
|
32
|
+
Nên thêm vào `.gitignore` của project:
|
|
33
|
+
|
|
34
|
+
```gitignore
|
|
35
|
+
.agent/.overwritten-*/
|
|
36
|
+
.agent/.install-manifest.json
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
## Muốn thay đổi framework một cách bền vững
|
|
40
|
+
|
|
41
|
+
Sửa trong **repo framework** rồi phát hành:
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
# trong repo sdd-framework
|
|
45
|
+
vim commands/generate-bdd.tmpl # hoặc steps/, rules/, modules/, templates/
|
|
46
|
+
npm run build # inline {{include}} → commands/*.md → core/ → .agent/
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
Rồi bump version + publish; project chạy `/update-framework` để nhận.
|
|
50
|
+
|
|
51
|
+
Nếu thay đổi chỉ đúng cho **một** project (quy ước riêng của repo đó), chỗ đúng để đặt là:
|
|
52
|
+
- `CLAUDE.md` — kiến trúc, layer, coding standard *(mọi lệnh đọc)*
|
|
53
|
+
- `.agent/project-context.yaml` — path, tech stack, routing service
|
|
54
|
+
- `.agent/project-lessons.md` — guardrail tích luỹ qua `/learn`
|
|
55
|
+
|
|
56
|
+
Ba chỗ đó đều **không** bị nâng cấp ghi đè.
|
package/core/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 :
|
|
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
|
-
•
|
|
44
|
-
• hoặc:
|
|
43
|
+
• /model → chọn model Opus
|
|
44
|
+
• hoặc: Settings → Model
|
|
45
45
|
|
|
46
|
-
Đang chạy
|
|
47
|
-
Y — đúng
|
|
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
|
|
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
|
|
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}
|
|
774
|
-
| /fix-bug |
|
|
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 :
|
|
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
|
-
•
|
|
41
|
-
• hoặc:
|
|
40
|
+
• /model → chọn model Opus
|
|
41
|
+
• hoặc: Settings → Model
|
|
42
42
|
|
|
43
|
-
Đang chạy
|
|
44
|
-
Y — đúng
|
|
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
|
|
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
|
|
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}
|
|
826
|
-
| /fix-bug |
|
|
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 :
|
|
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
|
-
•
|
|
47
|
-
• hoặc:
|
|
46
|
+
• /model → chọn model Opus
|
|
47
|
+
• hoặc: Settings → Model
|
|
48
48
|
|
|
49
|
-
Đang chạy
|
|
50
|
-
Y — đúng
|
|
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
|
|
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
|
|
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}
|
|
1062
|
-
| /fix-bug |
|
|
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 :
|
|
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
|
-
•
|
|
47
|
-
• hoặc:
|
|
46
|
+
• /model → chọn model Opus
|
|
47
|
+
• hoặc: Settings → Model
|
|
48
48
|
|
|
49
|
-
Đang chạy
|
|
50
|
-
Y — đúng
|
|
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
|
|
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
|
|
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}
|
|
786
|
-
| /fix-bug |
|
|
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/` |
|