@educa-corp/sdd-framework 0.6.0 → 0.7.1
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/gate-trace.js +25 -2
- package/bin/index.js +32 -5
- package/bin/lint-trace.js +41 -0
- package/bin/self-check.js +430 -3
- package/bin/trace-schema.json +418 -31
- package/core/FRAMEWORK_VERSION +1 -1
- package/{commands/extend-prd.md → core/commands/amend-prd.md} +206 -173
- package/core/commands/dev-run-test.md +48 -10
- package/core/commands/extend-prd.md +39 -12
- package/core/commands/generate-bdd.md +52 -10
- package/core/commands/generate-code.md +35 -2
- package/core/commands/generate-tech-docs.md +36 -4
- package/core/commands/map-testids.md +1 -1
- package/core/commands/qc-run-test.md +29 -3
- package/core/commands/refine-prd.md +13 -2
- package/core/commands/review-context.md +43 -8
- package/core/commands/sync.md +105 -1
- package/core/commands/validate-traces.md +289 -16
- package/core/rules/workflow.md +34 -0
- package/core/steps/context-loader.md +27 -6
- package/core/templates/feature.template +1 -1
- package/core/templates/project-context.yaml +3 -3
- package/core/templates/tech-design.template.md +2 -2
- package/docs/02-concepts/architecture.md +37 -1
- package/docs/02-concepts/overview.md +1 -1
- package/docs/02-concepts/pipeline-steps/02-specification.md +13 -7
- package/docs/02-concepts/pipeline-steps/07-dev-selftest.md +2 -0
- package/docs/02-concepts/pipeline-steps/08-qc-automation.md +1 -0
- package/docs/02-concepts/pipeline-steps/09-validate-traces.md +34 -3
- package/docs/02-concepts/pipeline-steps/10-feedback-loop.md +10 -1
- package/docs/02-concepts/traceability.md +187 -183
- package/docs/03-guides/architect.md +13 -4
- package/docs/03-guides/developer.md +1 -0
- package/docs/03-guides/product-owner.md +89 -72
- package/docs/03-guides/tester-qa.md +81 -81
- package/docs/04-reference/commands.md +148 -134
- package/docs/04-reference/trace-schema.md +45 -1
- package/docs/explain/02b-extend-prd.md +1 -1
- package/docs/explain/02c-amend-prd.md +152 -0
- package/docs/explain/06-generate-bdd.md +1 -1
- package/docs/explain/13-dev-run-test.md +15 -1
- package/docs/explain/19-qc-run-test.md +91 -87
- package/docs/explain/21-validate-traces.md +79 -75
- package/docs/explain/28-sync.md +25 -0
- package/docs/explain/README.md +136 -135
- package/package.json +1 -8
- package/commands/debug.md +0 -529
- package/commands/debug.tmpl +0 -260
- package/commands/define-product.md +0 -438
- package/commands/define-product.tmpl +0 -225
- package/commands/dev-gen-test.md +0 -700
- package/commands/dev-gen-test.tmpl +0 -490
- package/commands/dev-run-test.md +0 -435
- package/commands/dev-run-test.tmpl +0 -225
- package/commands/dev-smoke-test.md +0 -374
- package/commands/dev-smoke-test.tmpl +0 -217
- package/commands/extend-prd.tmpl +0 -273
- package/commands/fix-bug.md +0 -519
- package/commands/fix-bug.tmpl +0 -197
- package/commands/generate-architecture.md +0 -354
- package/commands/generate-architecture.tmpl +0 -197
- package/commands/generate-bdd.md +0 -923
- package/commands/generate-bdd.tmpl +0 -590
- package/commands/generate-code.md +0 -859
- package/commands/generate-code.tmpl +0 -649
- package/commands/generate-design-spec.md +0 -737
- package/commands/generate-design-spec.tmpl +0 -524
- package/commands/generate-prd.md +0 -722
- package/commands/generate-prd.tmpl +0 -226
- package/commands/generate-spec-manifest.md +0 -321
- package/commands/generate-spec-manifest.tmpl +0 -164
- package/commands/generate-tech-docs.md +0 -920
- package/commands/generate-tech-docs.tmpl +0 -273
- package/commands/learn.md +0 -399
- package/commands/learn.tmpl +0 -130
- package/commands/map-testids.md +0 -238
- package/commands/map-testids.tmpl +0 -81
- package/commands/propose-scenario.md +0 -359
- package/commands/propose-scenario.tmpl +0 -202
- package/commands/qc-analyze.md +0 -269
- package/commands/qc-analyze.tmpl +0 -112
- package/commands/qc-design-test.md +0 -226
- package/commands/qc-design-test.tmpl +0 -69
- package/commands/qc-plan.md +0 -206
- package/commands/qc-plan.tmpl +0 -49
- package/commands/qc-report.md +0 -217
- package/commands/qc-report.tmpl +0 -60
- package/commands/qc-review.md +0 -210
- package/commands/qc-review.tmpl +0 -53
- package/commands/qc-run-test.md +0 -326
- package/commands/qc-run-test.tmpl +0 -116
- package/commands/refine-prd.md +0 -653
- package/commands/refine-prd.tmpl +0 -281
- package/commands/report-bug.md +0 -305
- package/commands/report-bug.tmpl +0 -148
- package/commands/review-code.md +0 -415
- package/commands/review-code.tmpl +0 -146
- package/commands/review-context.md +0 -902
- package/commands/review-context.tmpl +0 -530
- package/commands/review-tech-docs.md +0 -561
- package/commands/review-tech-docs.tmpl +0 -404
- package/commands/setup-ai-first.md +0 -602
- package/commands/setup-ai-first.tmpl +0 -450
- package/commands/sync.md +0 -430
- package/commands/sync.tmpl +0 -429
- package/commands/update-framework.md +0 -203
- package/commands/update-framework.tmpl +0 -202
- package/commands/validate-traces.md +0 -1077
- package/commands/validate-traces.tmpl +0 -920
- package/hooks/data-guard.js +0 -232
- package/hooks/settings.json +0 -19
- package/modules/android-compose/module.yaml +0 -13
- package/modules/android-compose/stack-profile.yaml +0 -57
- package/modules/angular/architecture-snippets/component-patterns.md +0 -187
- package/modules/angular/module.yaml +0 -6
- package/modules/angular/stack-profile.yaml +0 -38
- package/modules/context-engineering/architecture-snippets/context-design.md +0 -119
- package/modules/context-engineering/module.yaml +0 -9
- package/modules/context-engineering/stack-profile.yaml +0 -61
- package/modules/dotnet/architecture-snippets/clean-arch.md +0 -160
- package/modules/dotnet/module.yaml +0 -6
- package/modules/dotnet/stack-profile.yaml +0 -50
- package/modules/flutter/module.yaml +0 -14
- package/modules/flutter/stack-profile.yaml +0 -59
- package/modules/golang/architecture-snippets/domain-layout.md +0 -283
- package/modules/golang/module.yaml +0 -6
- package/modules/golang/stack-profile.yaml +0 -40
- package/modules/ios-swiftui/module.yaml +0 -13
- package/modules/ios-swiftui/stack-profile.yaml +0 -55
- package/modules/java-spring/architecture-snippets/layered-arch.md +0 -201
- package/modules/java-spring/module.yaml +0 -15
- package/modules/java-spring/stack-profile.yaml +0 -28
- package/modules/nextjs/architecture-snippets/app-router-patterns.md +0 -269
- package/modules/nextjs/module.yaml +0 -14
- package/modules/nextjs/stack-profile.yaml +0 -74
- package/modules/nuxt/module.yaml +0 -14
- package/modules/nuxt/stack-profile.yaml +0 -58
- package/modules/phaser-game/architecture-snippets/phaser-scene-patterns.md +0 -646
- package/modules/phaser-game/module.yaml +0 -15
- package/modules/phaser-game/stack-profile.yaml +0 -90
- package/modules/php-laravel/architecture-snippets/service-repository.md +0 -302
- package/modules/php-laravel/module.yaml +0 -15
- package/modules/php-laravel/stack-profile.yaml +0 -56
- package/modules/qc-playwright/stack-profile.yaml +0 -66
- package/modules/react/architecture-snippets/hooks-query-patterns.md +0 -254
- package/modules/react/module.yaml +0 -14
- package/modules/react/stack-profile.yaml +0 -63
- package/modules/react-native/module.yaml +0 -14
- package/modules/react-native/stack-profile.yaml +0 -56
- package/modules/vue/module.yaml +0 -14
- package/modules/vue/stack-profile.yaml +0 -65
- package/rules/data-protection.md +0 -80
- package/rules/workflow.md +0 -99
- package/skills/code/SKILL.md +0 -19
- package/skills/code/SKILL.tmpl +0 -19
- package/skills/debug/SKILL.md +0 -19
- package/skills/debug/SKILL.tmpl +0 -19
- package/skills/design-spec/SKILL.md +0 -11
- package/skills/design-spec/SKILL.tmpl +0 -11
- package/skills/discovery/SKILL.md +0 -14
- package/skills/discovery/SKILL.tmpl +0 -14
- package/skills/prd/SKILL.md +0 -19
- package/skills/prd/SKILL.tmpl +0 -19
- package/skills/qc/qa-analyst/DOC_GAPS.template.md +0 -63
- package/skills/qc/qa-analyst/acceptance-criteria.md +0 -60
- package/skills/qc/qa-analyst/business-rules.md +0 -59
- package/skills/qc/qa-analyst/data-flow.md +0 -64
- package/skills/qc/qa-analyst/spec-breakdown.md +0 -61
- package/skills/qc/qa-designer/e2e/journey.md +0 -41
- package/skills/qc/qa-designer/exploratory/charter.md +0 -68
- package/skills/qc/qa-designer/exploratory/explore-to-functional.md +0 -43
- package/skills/qc/qa-designer/functional/api.md +0 -45
- package/skills/qc/qa-designer/functional/gui-feature.md +0 -46
- package/skills/qc/qa-designer/functional/gui-screen.md +0 -52
- package/skills/qc/qa-designer/integration/api.md +0 -42
- package/skills/qc/qa-designer/integration/db.md +0 -39
- package/skills/qc/qa-designer/integration/gui.md +0 -40
- package/skills/qc/qa-designer/integration/kafka.md +0 -40
- package/skills/qc/qa-designer/non-functional.md +0 -40
- package/skills/qc/qa-planner/test-plan.md +0 -120
- package/skills/qc/qa-reviewer/script/e2e.md +0 -87
- package/skills/qc/qa-reviewer/script/exploratory.md +0 -45
- package/skills/qc/qa-reviewer/script/functional.md +0 -101
- package/skills/qc/qa-reviewer/script/integration.md +0 -91
- package/skills/qc/qa-reviewer/script/non-functional.md +0 -126
- package/skills/qc/qa-reviewer/test-case/e2e.md +0 -73
- package/skills/qc/qa-reviewer/test-case/exploratory.md +0 -43
- package/skills/qc/qa-reviewer/test-case/functional.md +0 -76
- package/skills/qc/qa-reviewer/test-case/integration.md +0 -69
- package/skills/qc/qa-reviewer/test-case/non-functional.md +0 -73
- package/skills/qc/qa-runner/e2e.md +0 -49
- package/skills/qc/qa-runner/exploratory/session.md +0 -36
- package/skills/qc/qa-runner/functional/api.md +0 -35
- package/skills/qc/qa-runner/functional/gui-feature.md +0 -51
- package/skills/qc/qa-runner/functional/gui-screen.md +0 -55
- package/skills/qc/qa-runner/integration.md +0 -47
- package/skills/qc/qa-runner/non-functional.md +0 -49
- package/skills/qc/qa-runner/report/report.md +0 -37
- package/skills/setup-ai-first/SKILL.md +0 -19
- package/skills/setup-ai-first/SKILL.tmpl +0 -19
- package/skills/spec/SKILL.md +0 -19
- package/skills/spec/SKILL.tmpl +0 -19
- package/skills/test/SKILL.md +0 -18
- package/skills/test/SKILL.tmpl +0 -18
- package/steps/business-language.md +0 -56
- package/steps/capture-lesson.md +0 -112
- package/steps/context-loader.md +0 -406
- package/steps/gate.md +0 -151
- package/steps/report-footer.md +0 -125
- package/steps/review-fanout.md +0 -159
- package/steps/spawn-agent.md +0 -129
- package/steps/trace-mirror.md +0 -53
- package/templates/README.md +0 -70
- package/templates/architecture.template.md +0 -394
- package/templates/ci/trace-gate.yml +0 -146
- package/templates/design-spec.template.md +0 -217
- package/templates/feature.template +0 -123
- package/templates/hooks/pre-push +0 -61
- package/templates/platform-guide.template.md +0 -145
- package/templates/prd.template.md +0 -283
- package/templates/product-definition.template.md +0 -188
- package/templates/project-context.yaml +0 -212
- package/templates/tech-design.template.md +0 -490
|
@@ -6,6 +6,11 @@
|
|
|
6
6
|
> |---|---|---|
|
|
7
7
|
> | `/refine-prd` | *"PRD hiện tại có **vấn đề** gì?"* | 3 lăng kính review soi nội dung ĐANG CÓ |
|
|
8
8
|
> | **`/extend-prd`** | *"PRD hiện tại **thiếu** cái gì mới?"* | PO + hòm thư `prd-change-requests/` |
|
|
9
|
+
> | `/amend-prd` | *"một yêu cầu đang có cần **ĐỔI** thành gì?"* | PO khai tường minh ID cần sửa |
|
|
10
|
+
>
|
|
11
|
+
> **Ranh giới với `/amend-prd`:** lệnh này **chỉ THÊM** — Bước 5 §3 đòi output là *"superset chặt"*.
|
|
12
|
+
> Nó có **một** cửa sửa nội dung cũ (Bước 3.2 case 1, "mâu thuẫn rule") nhưng cửa đó **phái sinh**:
|
|
13
|
+
> chỉ mở khi phần THÊM làm một BR cũ sai. Muốn đổi một yêu cầu mà **không** thêm gì mới → `/amend-prd`.
|
|
9
14
|
>
|
|
10
15
|
> `/refine-prd` **không** thêm được UC/AC/BR mới — nó tự cấm ở Resume Mode Phase 2 (*"không thay đổi
|
|
11
16
|
> bất kỳ section nào không được tham chiếu bởi một finding được chấp nhận"*), và findings của nó sinh
|
|
@@ -274,8 +279,9 @@ Các từ như `cờ / flag`, `biến / trường / field`, `giá trị / value`
|
|
|
274
279
|
ℹ️ {n} file BDD đã sinh cho PRD này: {danh sách UC × platform}
|
|
275
280
|
Lệnh này CHỈ đánh số nối tiếp (UC{max_uc+1}, BR{max_br+1}) — KHÔNG bao giờ đánh lại
|
|
276
281
|
ID cũ, nên các liên kết @trace.business_rules hiện có KHÔNG bị ảnh hưởng.
|
|
277
|
-
Sau khi thêm:
|
|
278
|
-
|
|
282
|
+
Sau khi thêm: /generate-bdd cho UC MỚI, VÀ cho mỗi UC cũ mà Bước 3.2 kết luận là
|
|
283
|
+
"sửa BR/AC cũ" (BR đó đổi hành vi → BDD của nó lỗi thời thật → 🟠 PRD_DRIFT).
|
|
284
|
+
UC cũ KHÔNG bị sửa gì thì không phải gen lại (ⓘ PRD_STALE_REF).
|
|
279
285
|
```
|
|
280
286
|
|
|
281
287
|
---
|
|
@@ -340,7 +346,8 @@ Thêm : UC{max_uc+1} "{tên}" [hoặc: mở rộng UC{k}]
|
|
|
340
346
|
Sửa cái cũ : {danh sách BR/AC bị sửa do va chạm — hoặc "không"}
|
|
341
347
|
Từ request : {danh sách file request được đưa vào — hoặc "không"}
|
|
342
348
|
Version : {current} → {new} ({major|minor}) · Status → draft
|
|
343
|
-
BDD ảnh hưởng:
|
|
349
|
+
BDD ảnh hưởng: /generate-bdd cho UC mới{, và cho UC{k} vì BR8 bị sửa}
|
|
350
|
+
{n} UC cũ không đụng gì → KHÔNG phải gen lại
|
|
344
351
|
|
|
345
352
|
Tiếp tục? (Y/N)
|
|
346
353
|
```
|
|
@@ -406,10 +413,23 @@ Vị trí ghi từng loại nội dung:
|
|
|
406
413
|
2. Cập nhật Metadata: `Version` = mới · `Updated` = hôm nay · **`Status` = `draft`** *(thêm yêu cầu = phải duyệt lại)*.
|
|
407
414
|
3. Thêm row lên **đầu** bảng `# Change Log`:
|
|
408
415
|
```
|
|
409
|
-
| {new_version} | {today} | {
|
|
416
|
+
| {new_version} | {today} | {changelog_scope} |
|
|
417
|
+
```
|
|
418
|
+
**`{changelog_scope}` — mỗi mệnh đề mở đầu bằng UC SỞ HỮU** *(contract: `bin/trace-schema.json` → `changelog_row_contract`)*. Nguồn: UC mới (Bước 4) + **UC sở hữu mỗi BR/AC bị sửa** (kết luận Bước 3.2). Ngăn nhau bằng `;`. Nội dung không thuộc UC nào (§1c phụ thuộc, §1d quy ước) → `PRD-global`.
|
|
419
|
+
|
|
420
|
+
**Ví dụ đúng:**
|
|
421
|
+
```
|
|
422
|
+
thêm UC7 (xuất nhiều file): AC12-AC14, BR21-BR23; UC3: sửa BR8 (nâng giới hạn 5→20)
|
|
410
423
|
```
|
|
411
|
-
**Ví dụ
|
|
412
|
-
|
|
424
|
+
**Ví dụ SAI — mơ hồ:** `cập nhật theo yêu cầu mới` ← `/generate-bdd` sẽ khuyến nghị gen lại **toàn bộ**, và `/validate-traces` gắn `PRD_DRIFT` 🟠 cho **mọi** UC thay vì chỉ UC mới. Mất bộ lọc theo hướng **ỒN**.
|
|
425
|
+
|
|
426
|
+
**Ví dụ SAI — nêu BR mà bỏ UC sở hữu:** `…; sửa BR8 (nâng giới hạn 5→20)` ← thiếu `UC3:`.
|
|
427
|
+
|
|
428
|
+
> ⚠️ **Đây là ca nguy hiểm HƠN ca mơ hồ, và là lý do luật này thành contract (G53).** Row trên nêu rất nhiều ID nên **không** bị coi là mơ hồ. Nhưng `/validate-traces` Step 4 khớp bằng phép thử *"**UC** này có trong tập bị ảnh hưởng?"* — tập là `{UC7, AC12-14, BR21-23, BR8}`, và **UC3 không có trong đó**. Nên UC3 → ⓘ `PRD_STALE_REF` *"không phải lỗi"*, trong khi BR mà nó sở hữu **vừa đổi hành vi 5→20**.
|
|
429
|
+
>
|
|
430
|
+
> Và nó không dừng ở một cờ sai: rào an toàn của `--realign-prd-version` chỉ **từ chối khi UC là 🟠**. Ở đây nó là **ⓘ** ⇒ rào **mở cửa** ⇒ nhãn `prd_version` được dán lại trong cả TSV lẫn tag code ⇒ **cờ sạch vĩnh viễn trên một thay đổi chưa ai implement**. Mất bộ lọc theo hướng **IM LẶNG**.
|
|
431
|
+
>
|
|
432
|
+
> Viết `UC3:` là một tiền tố ba ký tự. Bỏ nó là mở một đường tự động che lỗi.
|
|
413
433
|
4. Cập nhật dòng đầu section: `> Hiện tại: **v{new}** ({today}) · Lịch sử đầy đủ → [changelog](./changelog/{TICKET-ID}-{prd-slug}.changelog.md)`
|
|
414
434
|
5. **Rollover** (cửa sổ trượt 5 row): bảng `# Change Log` vượt **5** row → chuyển mọi row vượt 5 (cũ nhất) sang **đầu** bảng của `{specs_dir}/{domain}/{prd-slug}/changelog/{TICKET-ID}-{prd-slug}.changelog.md`; PRD giữ 5 row gần nhất. Tạo dir + file theo skeleton của `/refine-prd` Phase 3 nếu chưa có.
|
|
415
435
|
|
|
@@ -440,13 +460,19 @@ Ví dụ footer cho lệnh này:
|
|
|
440
460
|
|
|
441
461
|
Version : v{old} → v{new} ({major|minor}) · Status → draft
|
|
442
462
|
Thêm : UC{N} "{tên}" · AC{a}-AC{b} · BR{c}-BR{d}
|
|
443
|
-
Sửa cũ : {BR8 — nâng giới hạn 5→20 | không}
|
|
463
|
+
Sửa cũ : {UC3: BR8 — nâng giới hạn 5→20 | không} ← LUÔN nêu UC sở hữu
|
|
444
464
|
Request : {2 file → archived/ (incorporated v{new}) | không}
|
|
445
|
-
Changelog : |
|
|
465
|
+
Changelog : | v2.0 | 2026-08-19 | thêm UC7: AC12-AC14, BR21-BR23; UC3: sửa BR8 (giới hạn 5→20) |
|
|
446
466
|
|
|
447
467
|
Guard sau-ghi : ✅ {n} UC · {m} AC · {k} BR · {j} changelog row cũ — còn nguyên
|
|
448
468
|
|
|
449
|
-
UC
|
|
469
|
+
UC BỊ SỬA nội dung ({n}): {UC3}
|
|
470
|
+
→ CẦN /generate-bdd rồi /generate-code cho các UC này — BR/AC của chúng vừa đổi hành vi.
|
|
471
|
+
/validate-traces sẽ xếp chúng vào 🟠 PRD_DRIFT (đúng).
|
|
472
|
+
❌ TUYỆT ĐỐI KHÔNG dùng --realign-prd-version cho chúng — đó là dán nhãn lên thay đổi
|
|
473
|
+
chưa ai implement.
|
|
474
|
+
|
|
475
|
+
UC KHÔNG đổi ({n}): {UC1, UC2, UC4…} ← = existing_ucs TRỪ danh sách "UC BỊ SỬA" ở trên
|
|
450
476
|
→ KHÔNG cần /generate-bdd hay /generate-code cho các UC này.
|
|
451
477
|
/validate-traces sẽ xếp chúng vào ⓘ PRD_STALE_REF (nhãn version cũ, nội dung không đổi).
|
|
452
478
|
Sạch bằng: /validate-traces --realign-prd-version {UC-ID}
|
|
@@ -466,7 +492,8 @@ Next : /refine-prd {prd-file} ← soi phần vừa thêm qua 3 lăng
|
|
|
466
492
|
• Feature CÓ màn hình → /generate-design-spec {prd-file} (design-spec sẽ tự
|
|
467
493
|
phát hiện lỗi thời vs PRD mới và bắt sign-off lại) rồi /generate-bdd
|
|
468
494
|
• Thuần backend → /generate-bdd {prd-file} thẳng
|
|
469
|
-
→
|
|
495
|
+
→ gen BDD/code cho UC MỚI **và** UC cũ bị sửa BR/AC (xem "UC BỊ SỬA nội dung").
|
|
496
|
+
CHỈ UC cũ không đụng gì mới dùng --realign-prd-version.
|
|
470
497
|
```
|
|
471
498
|
|
|
472
499
|
---
|
|
@@ -478,9 +505,9 @@ Next : /refine-prd {prd-file} ← soi phần vừa thêm qua 3 lăng
|
|
|
478
505
|
- [ ] Guard sau-ghi đã chạy và PASS: mọi UC/AC/BR/changelog row cũ còn nguyên
|
|
479
506
|
- [ ] Bước 3.2 đã hỏi đủ 3 câu va chạm (mâu thuẫn rule · trùng lặp · phụ thuộc)
|
|
480
507
|
- [ ] Mỗi AC mới có ≥1 ref `_(BR: …)_`; mỗi UC mới có dòng "AC liên quan"; hai chiều khớp nhau
|
|
481
|
-
- [ ] Dòng changelog **
|
|
508
|
+
- [ ] Dòng changelog: mỗi mệnh đề **mở đầu bằng UC sở hữu** (`UC3: sửa BR8`) — **không** BR/AC đứng một mình, **không** mơ hồ *(contract: `changelog_row_contract`; BR trơ trọi ⇒ UC đó thành ⓘ ⇒ `--realign` che lỗi)*
|
|
482
509
|
- [ ] `Status` đã reset về `draft`
|
|
483
510
|
- [ ] Hình dạng bảng BR giữ nguyên như cũ (không đổi 3-cột ↔ mở-cột ở lệnh này)
|
|
484
511
|
- [ ] Không có banned term; 0 thuật ngữ kỹ thuật/UI trong text mới
|
|
485
512
|
- [ ] Request đã xử lý → `incorporated` + `archived/` + commit; request chưa xử lý → giữ `Open`
|
|
486
|
-
- [ ] Report nêu
|
|
513
|
+
- [ ] Report nêu **CẢ HAI** danh sách: **UC BỊ SỬA nội dung** (→ `/generate-bdd`, cấm `--realign`) và **UC không đổi** (→ `--realign-prd-version`). Danh sách thứ hai = `existing_ucs` **TRỪ** danh sách thứ nhất — không được lấy trọn `existing_ucs`
|
|
@@ -222,11 +222,14 @@ Hỏi người dùng chọn platform target:
|
|
|
222
222
|
|
|
223
223
|
```
|
|
224
224
|
BDD này dành cho platform nào?
|
|
225
|
-
1. web
|
|
226
|
-
2. app
|
|
227
|
-
3.
|
|
225
|
+
1. web — FE/Web trong browser (React, Next.js, Angular, Vue, Nuxt)
|
|
226
|
+
2. app — Mobile native (Flutter, React Native, iOS, Android)
|
|
227
|
+
3. webview — Bundle web NHÚNG trong app native (Phaser game, mini-app)
|
|
228
|
+
4. system — System/BE BDD (tổng hợp từ BDD client có sẵn)
|
|
228
229
|
```
|
|
229
230
|
|
|
231
|
+
*Chỉ hiện những platform project thực sự dùng: nếu `services.{domain}` là map-theo-platform (context-loader 2b) thì lấy đúng các sub-key của nó làm danh sách; ngược lại hiện đủ bốn. `webview` là một **delivery surface** riêng — không phải `web` (browser) và không phải `app` (native) — nên nó có BDD, design-spec và sổ trace riêng.*
|
|
232
|
+
|
|
230
233
|
Chờ người dùng chọn. Set `active_platform` = giá trị đã chọn.
|
|
231
234
|
|
|
232
235
|
**Output path (spec repo mode):**
|
|
@@ -244,7 +247,7 @@ Chờ người dùng chọn. Set `active_platform` = giá trị đã chọn.
|
|
|
244
247
|
|
|
245
248
|
## System BDD Synthesis (active_platform = system)
|
|
246
249
|
|
|
247
|
-
*Chỉ áp dụng khi platform = system
|
|
250
|
+
*Chỉ áp dụng khi platform = `system`. Bỏ qua với mọi platform client (`web`/`app`/`webview`/…).*
|
|
248
251
|
|
|
249
252
|
### Step S0 — Brownfield Check
|
|
250
253
|
|
|
@@ -375,9 +378,37 @@ Chỉ cần kiểm tra trạng thái đã phân giải:
|
|
|
375
378
|
| `active_service` đã phân giải thành path service | Tiếp tục với `active_module` đã set. |
|
|
376
379
|
| `active_service = "multi"` **và** `service_candidates_kind = platform` (domain map-theo-platform, target PRD chưa gắn 1 platform) | Tiếp tục — BDD là artifact liên team, platform-split. Sinh `bdd/{platform}/` cho các platform có trong `service_candidates`; từ vựng lấy theo `service_candidates.{platform}.module`. KHÔNG cần chốt 1 service. Platform nào bị đánh dấu `unresolved` trong candidates (thiếu `prd_slug` tương ứng dưới `by_prd_slug`) → vẫn sinh BDD nhưng gắn ⚠️ nêu rõ chưa có repo nhận. |
|
|
377
380
|
| `active_service = "multi"` **và** `service_candidates_kind = prd_slug` | **DỪNG.** Candidates đang là map feature→repo, KHÔNG phải map platform — sinh `bdd/{slug}/` là sai bố cục. Yêu cầu người dùng chạy lại với target file cụ thể để `prd_slug` được xác định. |
|
|
378
|
-
| `active_service = "
|
|
381
|
+
| `active_service = "unrouted"` (chưa có mapping cho domain/platform/prd_slug này) | **TIẾP TỤC** — ghi `@trace.service: unrouted`, in ⚠️, **KHÔNG dừng**. Xem khối bên dưới. |
|
|
382
|
+
| `active_service = "unresolved"` (config **sai cấu trúc**: entry vừa có `path` vừa có `by_prd_slug`, hoặc `by_prd_slug` lồng nhau) | **DỪNG**, báo đúng key sai để người dùng sửa `project-context.yaml`. Đây là **bug cấu hình**, không phải trạng thái chờ. |
|
|
379
383
|
| Single-service (không có section `services`) | `active_module = tech_stack.module` (đã set ở Bước 6.5). Tiếp tục. |
|
|
380
384
|
|
|
385
|
+
#### `unrouted` — vì sao KHÔNG chặn ở đây *(G51)*
|
|
386
|
+
|
|
387
|
+
PRD và BDD là artifact **nghiệp vụ**. PO biết `domain` (auth, payment) và biết `platform`
|
|
388
|
+
(*"người dùng làm việc này trên web hay app?"*) — nhưng **không** biết code sẽ nằm repo nào,
|
|
389
|
+
và ở feature đầu tiên của một domain mới thì **chưa ai quyết**.
|
|
390
|
+
|
|
391
|
+
Chặn BDD vì lý do đó là đặt cổng **sai phase**: nó chặn phase KHÔNG CẦN biết, trong khi
|
|
392
|
+
`/generate-code` — phase **buộc phải** biết mới ghi được file — mới là chỗ đúng để chặn.
|
|
393
|
+
|
|
394
|
+
**Việc cần làm khi `unrouted`:**
|
|
395
|
+
1. `@trace.service: unrouted` vào header `.feature` (đừng để trống — cột 23 sẽ mất thông tin)
|
|
396
|
+
2. **`active_module` chưa biết** ⇒ hỏi người dùng `platform` trực tiếp (`web`/`app`/`system`) thay
|
|
397
|
+
vì suy từ module. Đây là câu hỏi **nghiệp vụ**, PO trả lời được. Từ vựng step lấy theo platform:
|
|
398
|
+
`web` → *clicks* · `app` → *taps* · `system` → *calls the API*.
|
|
399
|
+
3. In ⚠️ vào report:
|
|
400
|
+
```
|
|
401
|
+
⚠️ service: unrouted — chưa có mapping cho domain "{domain}"{ platform "{platform}"} trong
|
|
402
|
+
services: của project-context.yaml.
|
|
403
|
+
BDD đã sinh xong và ĐÚNG — đây là việc của architect, không phải của bạn.
|
|
404
|
+
Architect thêm mapping → /validate-traces tự nâng unrouted → path, KHÔNG cần chạy lại lệnh này.
|
|
405
|
+
/generate-code sẽ DỪNG cho tới khi có mapping (nó cần biết ghi vào repo nào).
|
|
406
|
+
```
|
|
407
|
+
|
|
408
|
+
> **Vì sao không cần chạy lại `/generate-bdd`:** `/validate-traces` đọc lại `services:` **mỗi lần
|
|
409
|
+
> chạy** và nâng `unrouted` → path khi mapping xuất hiện — cùng cách nó đã làm với `spec_ver`.
|
|
410
|
+
> Sổ **tự lành**.
|
|
411
|
+
|
|
381
412
|
### Phân giải `active_platform` (umbrella mode)
|
|
382
413
|
|
|
383
414
|
Umbrella mode không hỏi platform (khác spec repo mode) — nó **suy** từ module của service. Bắt buộc phải có giá trị: `active_platform` đi vào **path file**, vào **header `@trace.platform`**, và vào **tên sổ trace** `{UC-ID}-{platform}.tsv`.
|
|
@@ -411,7 +442,7 @@ Umbrella mode không hỏi platform (khác spec repo mode) — nó **suy** từ
|
|
|
411
442
|
|
|
412
443
|
## Design Spec — Gate & Load (chỉ FE/App)
|
|
413
444
|
|
|
414
|
-
*Chỉ chạy khi target platform là FE/App — spec mode: `active_platform
|
|
445
|
+
*Chỉ chạy khi target platform là FE/App — spec mode: `active_platform` là platform client (mọi giá trị **trừ** `system` — `web`, `app`, `webview`, `app-ios`, `app-android`, …); umbrella mode: `active_module` là module FE/App (react/nextjs/vue/nuxt/angular/flutter/react-native/ios-swiftui/android-compose). Bỏ qua HOÀN TOÀN với `system` và backend/brownfield.*
|
|
415
446
|
|
|
416
447
|
**1. Định vị design-spec của platform:**
|
|
417
448
|
`{paths.specs_dir}/{domain}/{prd-slug}/design-spec/{TICKET-ID}-design-spec-{active_platform}-{slug}.md`
|
|
@@ -505,7 +536,18 @@ Trước khi sinh, kiểm tra các file `.feature` có sẵn cho PRD này:
|
|
|
505
536
|
F — gen lại toàn bộ scenario
|
|
506
537
|
N — huỷ
|
|
507
538
|
```
|
|
508
|
-
3. Tiếp tục theo lựa chọn của người dùng
|
|
539
|
+
3. Tiếp tục theo lựa chọn của người dùng — nhưng **khuyến nghị Y hay F thì đọc `{changelog_scope}` của các row đó** *(contract: `bin/trace-schema.json` → `changelog_row_contract`; cùng dữ liệu `/validate-traces` Step 4 dùng để lọc 🟠 vs ⓘ)*:
|
|
540
|
+
|
|
541
|
+
Mỗi mệnh đề trong `{changelog_scope}` mở đầu bằng đơn vị sở hữu (`{UC-ID}:` hoặc `PRD-global:`). Dựng `affected_ucs` **theo đúng ba bước của `/validate-traces` Step 4**, gồm cả bước 2 — phép phân giải **`BR/AC → UC sở hữu`**: `BR{n}` → UC có BR đó trong bảng Business Rule (PRD §3) · `AC{n}` → UC có AC đó ở dòng `**AC liên quan:**`. Rồi:
|
|
542
|
+
|
|
543
|
+
| Tình trạng row trong khoảng | Khuyến nghị |
|
|
544
|
+
|---|---|
|
|
545
|
+
| **Bất kỳ** row **mơ hồ** (không nêu được đơn vị sở hữu, hoặc BR/AC không phân giải được về UC) | **F** — gen lại toàn bộ. Không chắc đổi ở đâu thì quét rộng |
|
|
546
|
+
| UC của target **có** trong `affected_ucs` | **Y** — cập nhật đúng scenario của UC đó |
|
|
547
|
+
| UC của target vào `affected_ucs` **CHỈ** qua mệnh đề mang hậu tố **`[no-behavior]`** | **N** — không có gì để gen lại; đó là thay đổi thuần cấu trúc, producer đã chứng minh không đổi hành vi |
|
|
548
|
+
| UC của target **không** có trong `affected_ucs` | **N** — bump này không đụng UC này. Nhãn version lệch sẽ được `/validate-traces --realign-prd-version` dọn |
|
|
549
|
+
|
|
550
|
+
> **Vì sao phải phân giải BR/AC (G53), không chỉ khớp UC-ID:** một row `thêm UC7: AC12-AC14; UC3: sửa BR8` là đúng contract. Nhưng nếu ai ghi thiếu `UC3:` — thành `…; sửa BR8` — thì row **không** mơ hồ (nó nêu đủ ID) mà UC3 vẫn không xuất hiện khi chỉ khớp UC-ID. Kết quả: khuyến nghị **N** cho đúng UC vừa bị đổi hành vi. Phân giải BR8 → UC3 là thứ chặn ca đó, và nó phải giống hệt phép phân giải của `/validate-traces` — hai consumer đọc cùng một dòng thì không được hiểu khác nhau.
|
|
509
551
|
|
|
510
552
|
---
|
|
511
553
|
|
|
@@ -602,7 +644,7 @@ Với mỗi UC, ghi vào path trên và set `# @trace.platform: {active_platform
|
|
|
602
644
|
# @trace.revision: 1 ← field tĩnh; version theo dõi bằng @trace.bdd_version
|
|
603
645
|
# @trace.domain: <domain>
|
|
604
646
|
# @trace.platform: {active_platform — web | app | system} ← BẮT BUỘC mọi mode; phải khớp segment bdd/{platform}/ của path
|
|
605
|
-
# @trace.service: {
|
|
647
|
+
# @trace.service: {service của ĐÚNG platform file này — BẮT BUỘC mọi mode. Nguồn của cột TSV `service`; trace gộp không tách theo service nên đây là chỗ DUY NHẤT mang thông tin sở hữu ở cấp row. Bốn giá trị: {path} · "unrouted" (chưa ai quyết repo — HỢP LỆ, cờ 🟠, KHÔNG chặn) · "unresolved" (config sai cấu trúc — bug) · "—" (single-service). KHÔNG ghi "multi": file này đã có MỘT platform xác định nên service_candidates.{platform}.path đã biết — ghi path đó (G51)}
|
|
606
648
|
# @trace.module: {active_module trong umbrella mode; "unknown" trong spec repo mode}
|
|
607
649
|
# @trace.status: draft
|
|
608
650
|
# @trace.author: AI-generated
|
|
@@ -756,7 +798,7 @@ In danh sách SC được bump vào report cuối để người dùng biết c
|
|
|
756
798
|
|
|
757
799
|
## Write Trace State
|
|
758
800
|
|
|
759
|
-
Sau khi sinh tất cả file `.feature`, tạo hoặc cập nhật **sổ trace theo platform** `{paths.trace_dir}/{domain}/{prd-slug}/{UC-ID}-{active_platform}.tsv` cho mỗi UC — một sổ riêng cho `system` / `web` / `app
|
|
801
|
+
Sau khi sinh tất cả file `.feature`, tạo hoặc cập nhật **sổ trace theo platform** `{paths.trace_dir}/{domain}/{prd-slug}/{UC-ID}-{active_platform}.tsv` cho mỗi UC — một sổ riêng cho mỗi platform (`system` / `web` / `app` / `webview` / …). Vì `sc_id` = `{UC-ID}-SC{N}` chỉ độc nhất trong (UC × platform) (mỗi platform tự đánh số SC từ 1), **mỗi platform một file** để scenario platform này không đè/xoá platform khác. Lệnh luôn biết `active_platform` (từ Platform Selection / Service Detection) nên chỉ ghi đúng sổ của platform đang gen.
|
|
760
802
|
|
|
761
803
|
> **Umbrella + `spec_source`:** cả file `.feature` **và** trace `.tsv` đều ghi vào **spec repo** (`{spec_source}/specs/{domain}/{prd-slug}/bdd/…` và `{spec_source}/.trace/{domain}/{prd-slug}/…`, do context-loader phân giải) — một thao tác ghi **single-repo**, commit/push vào spec submodule. (Trace được gộp trong spec repo để PM quản lý mọi status ở một chỗ; các lệnh phía code cập nhật liên-repo sau.)
|
|
762
804
|
|
|
@@ -816,7 +858,7 @@ sc_id\tsc_title\tspec_ver\tgen_ver\timplemented_by\ttest_count\ttest_classes\tde
|
|
|
816
858
|
| `fe_phase` | `—` (set bởi `/generate-code --phase` khi FE implement) |
|
|
817
859
|
| `status` | `UNTRACKED` |
|
|
818
860
|
| `last_updated` | hôm nay `YYYY-MM-DD` |
|
|
819
|
-
| `service` | `@trace.service` từ header `.feature` — đội/submodule sở hữu scenario này. `
|
|
861
|
+
| `service` | `@trace.service` từ header `.feature` — đội/submodule sở hữu scenario này. Bốn giá trị: `{path}` · **`unrouted`** (chưa ai quyết repo — hợp lệ, cờ 🟠) · `unresolved` (config sai cấu trúc — bug) · `—` (single-service). **Đừng bỏ trống** — trace gộp không tách theo service nên đây là chỗ DUY NHẤT mang thông tin sở hữu ở cấp row.<br>⚠️ **KHÔNG ghi `multi` vào file `.feature`** *(G51)*: khi split theo platform, mỗi file đã có **một** platform xác định nên `service_candidates.{platform}.path` **đã biết** — ghi path đó. `multi` chỉ là trạng thái trung gian ở cấp PRD trong bộ nhớ, không phải giá trị được ghi ra. |
|
|
820
862
|
| `design_spec_version` | `\| **Version** \|` của design-spec đã nạp ở §Design Spec — Gate & Load. `—` cho `system`/backend (không có design-spec), và `—` khi người dùng chọn "Y — vẫn sinh BDD" mà không có design-spec. |
|
|
821
863
|
|
|
822
864
|
## Refresh Panel Mirror
|
|
@@ -191,6 +191,39 @@ Lệnh này giới hạn nghiêm ngặt trong **một file feature** được tr
|
|
|
191
191
|
|
|
192
192
|
---
|
|
193
193
|
|
|
194
|
+
## Guard — biết ghi code vào REPO NÀO chưa *(chặn CỨNG — G51)*
|
|
195
|
+
|
|
196
|
+
*Chỉ áp ở umbrella/multi-service (có section `services`). Single-service thì bỏ qua.*
|
|
197
|
+
|
|
198
|
+
Đọc `@trace.service` từ header `.feature` target (và `service_root` từ context-loader Bước 1.6):
|
|
199
|
+
|
|
200
|
+
| Giá trị | Hành động |
|
|
201
|
+
|---|---|
|
|
202
|
+
| `{path}` — đã route | Tiếp tục. |
|
|
203
|
+
| **`unrouted`** | **DỪNG.** Chưa ai quyết repo cho domain này. |
|
|
204
|
+
| **`unresolved`** | **DỪNG.** Config sai cấu trúc. |
|
|
205
|
+
| `service_root = null` | **DỪNG.** Không có mốc thư mục để ghi file. |
|
|
206
|
+
|
|
207
|
+
```
|
|
208
|
+
🔴 Chưa biết ghi code vào repo nào — service của {UC-ID} đang là "{value}".
|
|
209
|
+
|
|
210
|
+
Lệnh này ghi file source TƯƠNG ĐỐI với service_root, nên không có mapping thì
|
|
211
|
+
không có chỗ ghi. (Trước G51 nó ghi source vào một thư mục tên đúng chữ
|
|
212
|
+
"unresolved/" — im lặng.)
|
|
213
|
+
|
|
214
|
+
Sửa: thêm mapping cho domain "{domain}" vào `services:` của .agent/project-context.yaml
|
|
215
|
+
rồi chạy /validate-traces (nó nâng unrouted → path, sổ tự lành), sau đó chạy lại lệnh này.
|
|
216
|
+
|
|
217
|
+
BDD của bạn KHÔNG sai và KHÔNG cần sinh lại — đây là bước cấu hình của architect.
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
> **Vì sao cổng nằm ở ĐÂY chứ không ở `/generate-bdd`** *(G51)*: PRD/BDD là artifact **nghiệp vụ** —
|
|
221
|
+
> PO biết `domain` và `platform`, không biết repo, và ở feature đầu tiên của domain mới thì chưa ai
|
|
222
|
+
> quyết. Trước G51 cổng đặt ngược: `/generate-bdd` **dừng hẳn** (phase không cần biết) còn lệnh này
|
|
223
|
+
> **không kiểm gì** (phase buộc phải biết). Đây là chỗ duy nhất thật sự không chạy nổi khi thiếu.
|
|
224
|
+
|
|
225
|
+
---
|
|
226
|
+
|
|
194
227
|
## Guard — BDD & Design Spec đã sẵn sàng chưa *(cảnh báo MỀM — đồng bộ generate-bdd)*
|
|
195
228
|
|
|
196
229
|
**BDD (mọi platform) — DS1:** đọc `# @trace.status:` từ header `.feature` target.
|
|
@@ -233,7 +266,7 @@ Lệnh này giới hạn nghiêm ngặt trong **một file feature** được tr
|
|
|
233
266
|
|
|
234
267
|
## Phase Detection
|
|
235
268
|
|
|
236
|
-
> **Nguồn chuẩn quyết BE/FE = `@trace.platform` của FILE FEATURE**
|
|
269
|
+
> **Nguồn chuẩn quyết BE/FE = `@trace.platform` của FILE FEATURE** — **`system` → BE · MỌI platform khác → FE** (`web`, `app`, `webview`, và bất kỳ surface nào project khai thêm). Luật viết bằng **phủ định**, không phải liệt kê: liệt kê `web`/`app` làm platform thứ tư không khớp nhánh nào, và lệnh sẽ phải tự đoán — sinh sai loại code mà không cờ nào báo. KHÔNG dùng `platform_type` (suy từ module) để quyết BE/FE — nó chỉ dùng cho **idiom stack/module** (cú pháp, layer, thư viện). Lý do: repo fullstack một-module (vd Next.js có API route) có `platform_type` cố định một giá trị, nhưng vẫn có cả feature `system` (BE) lẫn `web` (FE) — chỉ tag của chính feature mới đúng.
|
|
237
270
|
|
|
238
271
|
Parse `$ARGUMENTS` tìm flag `--phase` và `--force`:
|
|
239
272
|
|
|
@@ -242,7 +275,7 @@ Parse `$ARGUMENTS` tìm flag `--phase` và `--force`:
|
|
|
242
275
|
| `--phase=ui` | FE Phase 1 — sinh UI + layer mock API từ System BDD contract |
|
|
243
276
|
| `--phase=integration` | FE Phase 2 — thay mock adapter bằng lời gọi API thật từ tech docs |
|
|
244
277
|
| `--force` | "Gen lại tường minh" — **CHỈ** bỏ qua guard status ở §Read Trace State (không skip row đang `OK`). Xem định nghĩa hẹp bên dưới. |
|
|
245
|
-
| *(không có)* | Default — full:
|
|
278
|
+
| *(không có)* | Default — full: **`system`** → full backend; **mọi platform khác** (`web`/`app`/`webview`/…) → **FE full** (sinh UI + wire API thật trong một lần, không qua bước mock) |
|
|
246
279
|
|
|
247
280
|
> **`--force` có phạm vi HẸP — đây là ranh giới cứng, không phải khuyến nghị.**
|
|
248
281
|
> Nó bỏ qua **đúng một** thứ: luật "row `OK` thì skip" ở §Read Trace State. **Mọi guard khác giữ nguyên hiệu lực:** Scope Lock (cấm implement scenario của `.feature` khác) · quy tắc EXTEND phi-phá-huỷ (đọc lại trước khi ghi · CẤM full Write trên file đã tồn tại · output phải là superset chặt) · Guard sau-ghi · Fill-before-create · Build Verify.
|
|
@@ -232,7 +232,7 @@ Kiểm tra `output_path` đã tồn tại chưa.
|
|
|
232
232
|
|
|
233
233
|
- **Chưa tồn tại → chế độ FRESH.** Tạo doc từ template, chỉ điền (các) UC trong `input_features`. (Section của các UC không thuộc batch này giữ placeholder `{…}` / được thêm ở lần chạy sau.)
|
|
234
234
|
- **Đã tồn tại → chế độ APPEND.** Doc là tăng dần — không bao giờ regenerate từ đầu (sẽ đè mất chỉnh tay và sign-off của reviewer). Đọc bảng **§10 UC Coverage** và **Changelog** hiện có → `covered_ucs`. Với mỗi UC trong `input_features`, phân loại:
|
|
235
|
-
- **UC mới** (không có trong `covered_ucs`) → **thêm** các section của nó: sequence diagram §5 mới **đúng lane platform** (5.A/5.B/5.C, đánh số sau cái cuối cùng hiện có *trong lane đó*); với §4.5 — nếu **platform** này mới với doc → nhóm `### 4.5 — {platform}` mới, ngược lại thêm sub-block `§4.5.1.x {Screen} — {UC}` + row vào §4.5.6 dùng chung của nhóm platform đó (đừng lặp nhóm); row mới ở §3/§4.3/§8/§9. Rồi cập nhật §10 (row khoá theo platform×SC) và thêm một row Changelog
|
|
235
|
+
- **UC mới** (không có trong `covered_ucs`) → **thêm** các section của nó: sequence diagram §5 mới **đúng lane platform** (5.A/5.B/5.C, đánh số sau cái cuối cùng hiện có *trong lane đó*); với §4.5 — nếu **platform** này mới với doc → nhóm `### 4.5 — {platform}` mới, ngược lại thêm sub-block `§4.5.1.x {Screen} — {UC}` + row vào §4.5.6 dùng chung của nhóm platform đó (đừng lặp nhóm); row mới ở §3/§4.3/§8/§9. Rồi cập nhật §10 (row khoá theo platform×SC) và thêm một row Changelog **theo format ở Bước 1b**.
|
|
236
236
|
- **UC đã phủ được trỏ lại** (có trong `covered_ucs`) → đây là refresh/mở rộng có chủ đích (vd tech lead giờ trỏ vào BDD `web/` của một UC mà backend đã thiết kế, hoặc BDD bump version). Xác nhận trước khi đụng nội dung có sẵn:
|
|
237
237
|
```
|
|
238
238
|
↻ {UC-ID} đã có trong {TICKET-ID}-tech-design.md.
|
|
@@ -245,6 +245,38 @@ Lưu `mode` (`fresh` | `append`) và, theo từng UC của batch, hành động
|
|
|
245
245
|
|
|
246
246
|
---
|
|
247
247
|
|
|
248
|
+
## Bước 1b — Format row Changelog *(contract máy đọc — áp cho CẢ Fresh lẫn Append)*
|
|
249
|
+
|
|
250
|
+
Row Changelog của tech-doc **không phải ghi chú cho người đọc** — `/validate-traces` Step 5 đọc nó để quyết mỗi UC ăn cờ 🟠 `TECHDOC_DRIFT` hay ⓘ `TECHDOC_STALE_REF`.
|
|
251
|
+
|
|
252
|
+
Format *(contract: `bin/trace-schema.json` → `changelog_row_contract`)*:
|
|
253
|
+
|
|
254
|
+
```
|
|
255
|
+
| {revision} | {YYYY-MM-DD} | {changelog_scope} |
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
**`{changelog_scope}` — mỗi mệnh đề mở đầu bằng UC SỞ HỮU.** Nguồn: các UC trong `input_features` của batch vừa thêm/sửa (Bước 1 đã phân loại từng UC là `add-new` / `extend-platform` / `refresh` / `skip` — UC `skip` **KHÔNG** vào dòng này). Ngăn nhau bằng `;`. Nội dung không thuộc UC nào (§11 Cross-cutting, §2 kiến trúc chung) → `doc-global`.
|
|
259
|
+
|
|
260
|
+
| Ca | Ví dụ đúng |
|
|
261
|
+
|---|---|
|
|
262
|
+
| Fresh | `1 \| 2026-08-19 \| UC1, UC2: sinh lần đầu từ BDD system v1.4` |
|
|
263
|
+
| Thêm UC mới | `2 \| 2026-08-22 \| UC3: thêm §5.9 sequence + §10 coverage, từ BDD system v1.0` |
|
|
264
|
+
| Thêm platform cho UC đã phủ | `3 \| 2026-08-25 \| UC1: thêm block client web §4.5.1.2, từ BDD web v1.2` |
|
|
265
|
+
| Refresh vì BDD bump | `4 \| 2026-08-28 \| UC2: refresh §4.1 endpoint theo BDD system v1.6` |
|
|
266
|
+
| Chỉ sửa phần chung | `5 \| 2026-08-30 \| doc-global: bổ sung §11 chuẩn logging` |
|
|
267
|
+
|
|
268
|
+
*(Tech-doc **không** dùng hậu tố `[no-behavior]` — `doc-global` đã đủ: không nêu UC nào thì không UC nào ăn cờ. Marker đó chỉ dành cho producer biết chính xác `check_id` của từng fix mình vừa áp, tức `/review-context --fix`.)*
|
|
269
|
+
|
|
270
|
+
> **Vì sao khai format ở đây (G58).** Trước đó Bước 1 và §Sinh chỉ nói *"thêm một row Changelog"* — **không format, không ví dụ, không nhắc phải nêu UC**. Trong khi `/validate-traces` Step 5 lọc 🟠-vs-ⓘ **bằng chính row đó**, và chế độ APPEND bump `@trace.revision` chung cho cả doc nên **mọi UC cũ lệch revision** dù phần của chúng không đổi một dòng.
|
|
271
|
+
>
|
|
272
|
+
> Chỗ duy nhất có format là một **comment HTML** trong `templates/tech-design.template.md` — mà chế độ APPEND theo định nghĩa **không đọc lại template**. Nên contract đang phụ thuộc vào việc agent tình cờ nhìn thấy một dòng comment ở file khác. Chưa nổ vì ví dụ trong comment tình cờ đúng; đây là nợ chờ lệch, cùng lớp với G52/G53.
|
|
273
|
+
>
|
|
274
|
+
> Hai kiểu viết sai và hậu quả — **đối xứng hoàn toàn với phía PRD**:
|
|
275
|
+
> - **Mơ hồ** (`cập nhật tech design`) → Step 5 gắn 🟠 cho **MỌI** UC của doc. Ồn tới mức cờ mất giá trị.
|
|
276
|
+
> - **Nêu §/SC mà bỏ UC** (`thêm §5.9, §10`) → nêu đủ ID để **không** bị coi là mơ hồ, nhưng Step 5 khớp theo **UC**; nên UC vừa được thêm lại rơi vào ⓘ và `--realign-techdoc-revision` sẽ dán nhãn lại. Im lặng.
|
|
277
|
+
|
|
278
|
+
---
|
|
279
|
+
|
|
248
280
|
## Bước 2 — Cổng Chất lượng (mọi feature nguồn)
|
|
249
281
|
|
|
250
282
|
Với **mỗi** feature BDD trong scope:
|
|
@@ -346,7 +378,7 @@ Ghi/mở rộng `{output_path}` dùng template dưới đây, chỉ sinh **nội
|
|
|
346
378
|
- **§1/§2** (Overview/Actors, Architecture) là cấp PRD: viết ở lần chạy đầu; các lần sau chỉ mở rộng nếu batch thêm actor/integration thật sự mới.
|
|
347
379
|
- **§10 UC Coverage** — một row UC (có cột Platforms) + bảng con coverage-scenario khoá theo **(platform, SC)** — mỗi platform×SC một row, vì cùng số SC ở platform khác nhau là scenario khác nhau. Đây là mỏ neo mà chế độ APPEND đọc. Luôn cập nhật nó cho (các) UC/platform của batch.
|
|
348
380
|
|
|
349
|
-
**Chế độ APPEND (doc đã tồn tại):** **đừng** viết lại section có sẵn. Chèn diagram §5 của UC batch **vào đúng lane platform** (5.A/5.B/5.C, đánh số sau cái cuối trong lane đó, tiêu đề `platform · SC`), các row mới ở §3/§4.3/§8/§9; với §4.5 — platform mới → nhóm `### 4.5 — {platform}` mới, ngược lại thêm sub-block `§4.5.1.x {Screen} — {UC}` + row vào §4.5.6 dùng chung của nhóm (không lặp nhóm); rồi cập nhật §10 (row khoá theo platform×SC) và thêm một row Changelog
|
|
381
|
+
**Chế độ APPEND (doc đã tồn tại):** **đừng** viết lại section có sẵn. Chèn diagram §5 của UC batch **vào đúng lane platform** (5.A/5.B/5.C, đánh số sau cái cuối trong lane đó, tiêu đề `platform · SC`), các row mới ở §3/§4.3/§8/§9; với §4.5 — platform mới → nhóm `### 4.5 — {platform}` mới, ngược lại thêm sub-block `§4.5.1.x {Screen} — {UC}` + row vào §4.5.6 dùng chung của nhóm (không lặp nhóm); rồi cập nhật §10 (row khoá theo platform×SC) và thêm một row Changelog **theo format ở Bước 1b**. Bump `@trace.revision` và làm mới `@trace.ucs` / `@trace.platforms` ở header, và cập nhật entry của platform vừa đụng trong map `@trace.bdd_versions` (vd set `web=2.0`, giữ nguyên `system`).
|
|
350
382
|
|
|
351
383
|
<!--
|
|
352
384
|
════════════════════════════════════════════════════════════════════════════
|
|
@@ -389,7 +421,7 @@ Ghi/mở rộng `{output_path}` dùng template dưới đây, chỉ sinh **nội
|
|
|
389
421
|
@trace.ucs: {TICKET-ID}-UC1, {TICKET-ID}-UC2{, …}
|
|
390
422
|
@trace.service: {service — từ header BDD @trace.service}
|
|
391
423
|
@trace.module: {module liên quan — vd dotnet, angular}
|
|
392
|
-
@trace.platforms: {system | web | app — tuỳ thư mục BDD nào tồn tại}
|
|
424
|
+
@trace.platforms: {system | web | app | webview | … — tuỳ thư mục BDD nào tồn tại}
|
|
393
425
|
@trace.bdd_versions: {MAP theo từng platform — số nhiều, KHÁC @trace.bdd_version (scalar) của .feature — vd system=1.5, web=1.9, app=1.7; chỉ platform có mặt. Mỗi feature mang bdd_version riêng; đừng gộp về một số.}
|
|
394
426
|
@trace.api_source: {existing | —}
|
|
395
427
|
@trace.revision: 1
|
|
@@ -762,7 +794,7 @@ sequenceDiagram
|
|
|
762
794
|
|
|
763
795
|
| UC | Feature | Platforms | Section phủ | Trạng thái |
|
|
764
796
|
|----|---------|-----------|------------------|--------|
|
|
765
|
-
| {TICKET-ID}-UC1 | {title} | {system, web, app} | §… | ✅ Covered |
|
|
797
|
+
| {TICKET-ID}-UC1 | {title} | {system, web, app, webview…} | §… | ✅ Covered |
|
|
766
798
|
|
|
767
799
|
### Độ phủ Scenario UC1
|
|
768
800
|
|
|
@@ -180,7 +180,7 @@ placeholder bên dưới sẽ rỗng và lệnh sẽ đọc/ghi sai chỗ.
|
|
|
180
180
|
|
|
181
181
|
Phân giải `platform` từ `@trace.platform` / `platform_type`. Test-id là chuyện của **FE/App** — nếu `system` / backend → HALT:
|
|
182
182
|
```
|
|
183
|
-
❌ /map-testids chỉ áp dụng cho
|
|
183
|
+
❌ /map-testids chỉ áp dụng cho platform CLIENT (mọi platform trừ `system` — web/app/webview/…). BE không có UI test-id.
|
|
184
184
|
```
|
|
185
185
|
Phân giải attribute test-id từ `@trace.testid_attr` (hoặc theo module): web `data-testid` · React Native `testID` · Flutter `Key`/`Semantics(identifier:)` · native iOS `accessibilityIdentifier`.
|
|
186
186
|
|
|
@@ -222,7 +222,7 @@ Sau khi chạy, cập nhật **sổ của platform đang test** `{paths.trace_di
|
|
|
222
222
|
|
|
223
223
|
| Cột | Giá trị |
|
|
224
224
|
|--------|-------|
|
|
225
|
-
| `qc_status` | `pass` nếu mọi QC test của SC này pass · `fail` nếu có cái fail · `skip` nếu tất cả skip/xfail · `not_run` nếu không QC test nào phủ
|
|
225
|
+
| `qc_status` | Đọc cột `status` của row **TRƯỚC** — xem §Guard ngay dưới bảng. Row `OK`/`GAP`/`UNTRACKED`: `pass` nếu mọi QC test của SC này pass · `fail` nếu có cái fail · `skip` nếu tất cả skip/xfail · `not_run` nếu không QC test nào phủ nó. Row **`DRIFT`/`ORPHANED`**: **không bao giờ ghi `pass`** — hạ về `not_run` |
|
|
226
226
|
| `qc_run_at` | hôm nay `YYYY-MM-DD` |
|
|
227
227
|
| `last_updated` | hôm nay `YYYY-MM-DD` |
|
|
228
228
|
| `qc_owner` | **SC đang chờ ai** (view "pending" của PM/PO): `dev` nếu FAIL = product-gap (defect thật → dev fix) · `po` nếu `skip`/`not_run` vì một **`DOC_GAPS` 🔴 Blocker đang open** chặn test (PO phải làm rõ PRD/BDD) · `—` nếu `pass`, hoặc FAIL = script-bug (QC tự fix — tạm thời) |
|
|
@@ -232,9 +232,35 @@ Set `qc_owner`/`qc_blocked_by` cùng với `qc_status`. Khi `pass`, **clear** c
|
|
|
232
232
|
Với FAIL product-gap, set `qc_owner=dev` ngay; `BUG-{id}` được backfill vào `qc_blocked_by`
|
|
233
233
|
khi QC chạy `/report-bug` mà `/qc-report` nhắc.
|
|
234
234
|
|
|
235
|
+
### Guard — ĐỌC `status` trước khi ghi `pass` *(bắt buộc)*
|
|
236
|
+
|
|
237
|
+
*Contract: `bin/trace-schema.json` → `positive_assertion_guards`. Đối xứng hoàn toàn với `/dev-run-test`; dữ liệu đã có trong sổ, không phát sinh I/O.*
|
|
238
|
+
|
|
239
|
+
`pass` **không** mang nghĩa *"QC test đã chạy và xanh"*. Nó mang nghĩa **"scenario này đã được nghiệm thu theo spec HIỆN TẠI"**.
|
|
240
|
+
|
|
241
|
+
| `status` của row | `qc_status` ghi gì | `qc_run_at` |
|
|
242
|
+
|---|---|---|
|
|
243
|
+
| `OK` · `GAP` · `UNTRACKED` | như bảng trên | hôm nay |
|
|
244
|
+
| **`DRIFT`** | test **pass** → **`not_run`** *(KHÔNG `pass`)* · **fail** → **`fail`** như thường · **skip** → `skip` như thường | `—` nếu ghi `not_run` |
|
|
245
|
+
| **`ORPHANED`** | **`not_run`** — scenario đã bị xoá khỏi `.feature` | `—` |
|
|
246
|
+
|
|
247
|
+
**Chỉ `pass` bị chặn.** `fail` là tin xấu thật, `skip` là giá trị trung tính — cả hai không phải lời khẳng định nên ghi bình thường. Chặn chúng là biến một guard chống-báo-cáo-sai thành một guard che-tin-xấu.
|
|
248
|
+
|
|
249
|
+
Khi hạ về `not_run` vì `DRIFT`/`ORPHANED`, **KHÔNG** clear `qc_owner`/`qc_blocked_by` và **KHÔNG** chạy §Đóng bug đã verify — hai bước đó chỉ dành cho `pass` **thật**. Đóng một bug dựa trên một lần QC chạy trên spec đã đổi là đóng sai. In:
|
|
250
|
+
```
|
|
251
|
+
⚠️ {sc_id} — QC test XANH nhưng row đang {DRIFT | ORPHANED}, nên KHÔNG ghi pass.
|
|
252
|
+
Không bug nào được đóng ở lần chạy này cho SC đó.
|
|
253
|
+
Làm: /generate-code {UC-ID} → /qc-design-test lại → chạy lại lệnh này.
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
> **Vì sao (GAPS-v4 G55).** Bản cũ khai `qc_status` **trực giao** với `status` — trực giao về *kết quả chạy* thì đúng, nhưng **không** trực giao về *quyền được khẳng định*. `/generate-bdd` hạ `qc_status → not_run` khi spec đổi (kèm lý do *"cái này làm cờ nói dối"*), rồi lần `/qc-run-test` kế tiếp dựng lại `pass` với ngày mới. Ở đây hậu quả còn đi xa hơn `/dev-run-test`: một `pass` sai còn **đóng một bug** (§Đóng bug đã verify) — nên guard phải chặn cả nhánh đó.
|
|
257
|
+
>
|
|
258
|
+
> **Tầng thứ hai độc lập:** `lint-trace` **T12** bắt đúng trạng thái này ở sổ thật, bất kể lệnh nào ghi ra.
|
|
259
|
+
|
|
235
260
|
Giữ nguyên mọi cột khác — **không bao giờ** đụng `dev_selftest`/`dev_selftest_at`
|
|
236
|
-
(do `/dev-run-test` sở hữu). `qc_status` (QC chính thức) và
|
|
237
|
-
hai tín hiệu riêng; cả hai trực giao với `status`
|
|
261
|
+
(do `/dev-run-test` sở hữu; nó có guard riêng cùng loại). `qc_status` (QC chính thức) và
|
|
262
|
+
`dev_selftest` (dev smoke) là hai tín hiệu riêng; cả hai trực giao với `status` về **kết quả
|
|
263
|
+
chạy**, nhưng **KHÔNG** trực giao về **quyền khẳng định `pass`** — xem §Guard ở trên.
|
|
238
264
|
|
|
239
265
|
## Đóng bug đã verify *(chạy TRƯỚC khi clear `qc_blocked_by`)*
|
|
240
266
|
|
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
# /refine-prd — Phân tích PRD qua 3 lăng kính review
|
|
2
2
|
|
|
3
|
+
> **Ranh giới — lệnh này chỉ áp được fix cho vấn đề mà CHÍNH NÓ tìm ra.** Resume Mode Phase 2 tự
|
|
4
|
+
> cấm đụng bất kỳ section nào không được một finding chấp nhận trỏ tới, và findings sinh từ việc soi
|
|
5
|
+
> PRD hiện có — nên **không có đường nào để một ý định MỚI của PO đi vào**.
|
|
6
|
+
> Thêm UC/AC/BR mới → `/extend-prd`. **Đổi** một yêu cầu đang đúng cú pháp → **`/amend-prd`**.
|
|
7
|
+
|
|
3
8
|
## Gate
|
|
4
9
|
|
|
5
10
|
*Checkpoint: **chặn CỨNG** — --resume áp findings trực tiếp vào PRD. `--yes` KHÔNG bỏ qua được (gate Bước 3a).*
|
|
@@ -621,9 +626,15 @@ Cập nhật `status: "applied"` ở **root level** của file findings (không
|
|
|
621
626
|
5. Cập nhật `# Change Log` của PRD — **bảng phẳng 1 dòng/version, cửa sổ trượt 5 entry** (nếu gặp format cũ `### v{X}` block → chuẩn hoá sang bảng phẳng khi cập nhật):
|
|
622
627
|
- Thêm row mới lên **đầu** bảng:
|
|
623
628
|
```
|
|
624
|
-
| {new_version} | {today} | {
|
|
629
|
+
| {new_version} | {today} | {changelog_scope} |
|
|
625
630
|
```
|
|
626
|
-
|
|
631
|
+
**`{changelog_scope}` — mỗi mệnh đề mở đầu bằng UC SỞ HỮU** *(contract: `bin/trace-schema.json` → `changelog_row_contract`)*. Nguồn: `uc_id` / `section` của các finding được chấp nhận. Ngăn nhau bằng `;`; finding global (`uc_id: ""`) → `PRD-global`.
|
|
632
|
+
|
|
633
|
+
**Ví dụ đúng:** `UC2: sửa BR5, thêm AC7; PRD-global: làm rõ scope §1`
|
|
634
|
+
|
|
635
|
+
⚠️ **BR/AC không bao giờ đứng một mình.** `sửa BR5` (thiếu `UC2:`) nêu đủ nhiều ID để **không** bị coi là mơ hồ, nhưng `/validate-traces` Step 4 khớp bằng phép thử *"**UC** này có trong tập?"* — nên UC2 rơi vào ⓘ `PRD_STALE_REF` trong khi BR5 của nó vừa đổi, và `--realign-prd-version` (chỉ chặn 🟠) sẽ dán nhãn version lại lên đó. Đây là G53: mất bộ lọc theo hướng **im lặng**, nguy hiểm hơn hướng mơ hồ/ồn.
|
|
636
|
+
|
|
637
|
+
*(Consumer của dòng này: `/generate-bdd` Version Check — biết scenario nào cần cập nhật; `/validate-traces` Step 4 — lọc 🟠 `PRD_DRIFT` vs ⓘ `PRD_STALE_REF`.)*
|
|
627
638
|
- Cập nhật dòng đầu section: `> Hiện tại: **v{new_version}** ({today}) · Lịch sử đầy đủ → [changelog](./changelog/{TICKET-ID}-{prd-slug}.changelog.md)`
|
|
628
639
|
- **Rollover (giữ PRD gọn — đây là chuẩn chung, /review-context cũng theo):** nếu bảng `# Change Log` có **> 5 row** → chuyển **mọi row vượt 5** (cũ nhất) sang **đầu** bảng của file kho `{paths.specs_dir}/{domain}/{prd-slug}/changelog/{TICKET-ID}-{prd-slug}.changelog.md` (giữ thứ tự mới→cũ); PRD chỉ giữ **5 row gần nhất**. Tạo thư mục `changelog/` + file kho nếu chưa có, theo skeleton:
|
|
629
640
|
```
|
|
@@ -760,14 +760,21 @@ Với mỗi finding có `auto_fixable: true`, theo thứ tự (critical → majo
|
|
|
760
760
|
|
|
761
761
|
**Với file PRD:**
|
|
762
762
|
|
|
763
|
-
| check_id | Áp dụng gì |
|
|
764
|
-
|
|
765
|
-
| P1 (Banned term) | Thay mọi lần xuất hiện banned term bằng canonical term |
|
|
766
|
-
| P1 (Thuật ngữ kỹ thuật/UI) | Diễn đạt lại theo Business Language Guard (Nhóm 1) / chuyển Design Spec (2) / bỏ về Tech Docs (3) |
|
|
767
|
-
| P4 (Structure) | Thêm skeleton section/metadata còn thiếu (row Status vắng → thêm mặc định `draft`); greenfield → xoá section "Existing API Contract" rỗng |
|
|
763
|
+
| check_id | Áp dụng gì | Đổi hành vi? |
|
|
764
|
+
|----------|--------------|:---:|
|
|
765
|
+
| P1 (Banned term) | Thay mọi lần xuất hiện banned term bằng canonical term | **CÓ** |
|
|
766
|
+
| P1 (Thuật ngữ kỹ thuật/UI) | Diễn đạt lại theo Business Language Guard (Nhóm 1) / chuyển Design Spec (2) / bỏ về Tech Docs (3) | **CÓ** |
|
|
767
|
+
| P4 (Structure) | Thêm skeleton section/metadata còn thiếu (row Status vắng → thêm mặc định `draft`); greenfield → xoá section "Existing API Contract" rỗng | KHÔNG |
|
|
768
768
|
|
|
769
769
|
> **Chạy Business Language Guard trên text vừa sửa TRƯỚC khi ghi** (xem section "Ngôn ngữ nghiệp vụ") — không để bản auto-fix tự kéo thuật ngữ kỹ thuật vào.
|
|
770
770
|
|
|
771
|
+
**Cột "Đổi hành vi?" là đầu vào của Phase 3** — nó quyết định UC bị đụng có ăn cờ 🟠 `PRD_DRIFT` hay ở lại ⓘ. Ghi lại `check_id` + `uc_id` của **từng** finding vừa áp; Phase 3 cần cả hai.
|
|
772
|
+
|
|
773
|
+
| | Nghĩa | Vì sao |
|
|
774
|
+
|---|---|---|
|
|
775
|
+
| **CÓ** | Câu văn nghiệp vụ trong PRD đã khác đi | P1 banned-term: term đó **cũng nằm trong `.feature` đã sinh** nên BDD lỗi thời thật về thuật ngữ (B2/C4 sẽ bắt) — đổi từ trong PRD mà không nêu UC là **bỏ sót**, không phải trung tính. P1 tech-jargon: auto-fix của nó **viết lại câu** AC/BR, và nhánh 2/3 **lấy nội dung ra khỏi** PRD |
|
|
776
|
+
| **KHÔNG** | Chỉ thêm/bỏ vỏ cấu trúc, 0 nội dung nghiệp vụ mới | Thêm một heading rỗng hay row `Status` mặc định không làm BDD của UC đó lỗi thời. Đánh dấu nó là drift chính là **báo động giả** |
|
|
777
|
+
|
|
771
778
|
**Với file BDD:**
|
|
772
779
|
|
|
773
780
|
| check_id | Áp dụng gì |
|
|
@@ -786,8 +793,29 @@ Sau khi áp dụng mỗi finding, đánh dấu nó `status: "applied"` + `applie
|
|
|
786
793
|
|
|
787
794
|
### Phase 3 — Version bump
|
|
788
795
|
|
|
789
|
-
- **PRD**: nếu ≥1 finding được áp dụng → bump version **minor** (auto-fix
|
|
790
|
-
|
|
796
|
+
- **PRD**: nếu ≥1 finding được áp dụng → bump version **minor** (auto-fix **không bao giờ thêm/xoá UC và không tái cấu trúc scope** — kể cả P1 tech-jargon nhánh 2/3, thứ nó di dời là *chi tiết cơ chế* xuống đúng tầng, ý định nghiệp vụ không đổi; nên minor luôn đúng), **reset `| **Status** | draft |` trong Metadata** (PRD vừa đổi sau khi duyệt → con dấu duyệt cũ hết hiệu lực, phải duyệt lại — đồng bộ với /refine-prd), thêm entry Changelog:
|
|
797
|
+
|
|
798
|
+
`| {new_version} | {today} | Auto-fix — {changelog_scope} |` — bảng phẳng + **rollover giữ 5 row gần nhất** (dồn dư sang `changelog/{TICKET-ID}-{prd-slug}.changelog.md`); xem quy ước đầy đủ ở refine-prd Phase 3.
|
|
799
|
+
|
|
800
|
+
**`{changelog_scope}` — BẮT BUỘC, dựng từ `uc_id` + `check_id` của các finding `status: applied`** *(contract: `bin/trace-schema.json` → `changelog_row_contract`)*:
|
|
801
|
+
|
|
802
|
+
1. Gom các finding vừa áp theo `uc_id`. `uc_id: ""` → nhóm `PRD-global`.
|
|
803
|
+
2. Mỗi nhóm thành một mệnh đề `{uc_id}: {tóm tắt các check}`, ngăn nhau bằng `;`.
|
|
804
|
+
3. Nhóm mà **mọi** finding trong đó đều ở hàng **"Đổi hành vi? KHÔNG"** (Phase 2) → gắn hậu tố **`[no-behavior]`**. Nhóm có **dù chỉ một** finding "CÓ" → **KHÔNG** gắn.
|
|
805
|
+
|
|
806
|
+
```
|
|
807
|
+
| 1.4 | 2026-08-19 | Auto-fix — UC5: banned-term (khách hàng→người mua); PRD-global: skeleton §4b [no-behavior] |
|
|
808
|
+
```
|
|
809
|
+
|
|
810
|
+
→ `/validate-traces`: **UC5 🟠 `PRD_DRIFT`** (đúng — có sửa thật) · **các UC còn lại ⓘ `PRD_STALE_REF`** (đúng — không đụng).
|
|
811
|
+
|
|
812
|
+
> **Vì sao BẮT BUỘC (G52).** Bản cũ ghi cứng `Auto-fix: applied {N} auto-fixable findings` — **không nêu UC nào**. `/validate-traces` Step 4 lọc 🟠-vs-ⓘ bằng cách hỏi *"row changelog có nêu UC này không"*, và một row không nêu gì thì rơi vào lưới an toàn *"mơ hồ → 🟠 cho **MỌI** UC"*. Nên sửa một từ trong UC5 của PRD 8 UC làm **cả 8 UC** ăn cờ 🟠 và route sang `/generate-bdd`.
|
|
813
|
+
>
|
|
814
|
+
> Lưới an toàn đó **đúng khi thiếu thông tin** — nhưng ở đây **không thiếu**: findings YAML có `uc_id` **bắt buộc** cho mỗi finding, và Phase 2 vừa đánh dấu `status: applied` cho từng cái. Lệnh **đang cầm** câu trả lời lúc nó ghi dòng đó, rồi vứt đi.
|
|
815
|
+
>
|
|
816
|
+
> Cái mất không phải 7 lần kiểm vô ích. `--fix` là đường rẻ nhất trong lane PO nên nó chạy nhiều nhất; sau vài sprint `PRD_DRIFT` sáng thường trực, **người đọc học cách bỏ qua, rồi lần lệch THẬT cũng bị bỏ qua cùng** — chính câu `/validate-traces` Step 4 dùng để biện minh cho bộ lọc.
|
|
817
|
+
>
|
|
818
|
+
> **Cách làm đúng đã có sẵn ngay dưới đây, ở nhánh BDD:** *"tăng `sc_version` của **đúng scenario đó**… Scenario không bị sửa → **giữ nguyên**… bump vô cớ tạo `DRIFT` giả và làm cờ mất giá trị"*. Nhánh BDD phân loại check theo *có đổi thân scenario hay không* rồi chỉ đánh dấu đơn vị bị đụng. Ba bước trên là **đúng cách đó**, áp cho PRD.
|
|
791
819
|
- **BDD**: nếu ≥1 finding được áp dụng → tăng `@trace.bdd_version` lên 0.1, **reset `# @trace.status: draft`** trong header (BDD đổi sau khi duyệt → phải duyệt lại — đồng bộ với cơ chế reset draft của PRD)
|
|
792
820
|
- **BDD — `@trace.sc_version` theo từng scenario (BẮT BUỘC):** với **mỗi scenario có ≥1 finding được áp dụng làm đổi thân nó** — R3 (diễn đạt lại step), R7 (thay giá trị cụ thể), R9 (thêm cột data table), R10 (thêm Note), B6 (thêm `And` side-effect), B2 (đổi tên entity/field trong step/table) — tăng `# @trace.sc_version` của **đúng scenario đó** lên 0.1. Scenario không bị sửa → **giữ nguyên**.
|
|
793
821
|
- Đây là tín hiệu DUY NHẤT cho `/validate-traces` biết code của SC đó đã lỗi thời (`spec_ver != gen_ver` → `DRIFT`). `bdd_version` ở cấp file không đủ phân giải để biết SC nào cần regen.
|
|
@@ -808,6 +836,9 @@ Còn pending (cần quyết định của con người): {N}
|
|
|
808
836
|
- F00X [{severity}] {tóm tắt finding} ← mở file findings trong Review Board
|
|
809
837
|
|
|
810
838
|
{If PRD}: Version bumped: {old} → {new} | Status: reset về draft (cần duyệt lại)
|
|
839
|
+
{If PRD}: Changelog : | {new} | {today} | {changelog_scope} |
|
|
840
|
+
↳ UC sẽ hiện 🟠 PRD_DRIFT: {UC5} · UC ở lại ⓘ STALE_REF: {UC1-4, UC6-8}
|
|
841
|
+
(nhóm [no-behavior] và UC không đụng → KHÔNG cần /generate-bdd)
|
|
811
842
|
{If BDD}: bdd_version: {old} → {new} | @trace.status: reset về draft (cần duyệt lại)
|
|
812
843
|
{If BDD, chỉ khi có ≥1 SC bump}: sc_version: {UC-ID}-SC2 1.0→1.1, {UC-ID}-SC5 1.2→1.3
|
|
813
844
|
↳ {n} SC này sẽ hiện DRIFT ở /validate-traces → /generate-code {feature-file} để sinh lại
|
|
@@ -862,7 +893,8 @@ Với mỗi finding `accepted`/`modified` sau khi áp xong → đặt `status: "
|
|
|
862
893
|
| P4 (Structure) | Thêm section/metadata field còn thiếu (row Status vắng → thêm mặc định `draft`) |
|
|
863
894
|
| P5 (Custom) | Áp dụng như nêu trong suggestion/note |
|
|
864
895
|
|
|
865
|
-
→ Sau khi áp dụng, bump version PRD (minor), **reset `| **Status** | draft |` trong Metadata** (PRD vừa đổi sau khi duyệt → phải duyệt lại — đồng bộ với /refine-prd), thêm row Changelog
|
|
896
|
+
→ Sau khi áp dụng, bump version PRD (minor), **reset `| **Status** | draft |` trong Metadata** (PRD vừa đổi sau khi duyệt → phải duyệt lại — đồng bộ với /refine-prd), thêm row Changelog `| {new_version} | {today} | {changelog_scope} |` (bảng phẳng + **rollover giữ 5 row gần nhất** dồn dư sang `changelog/` — xem quy ước ở refine-prd Phase 3), và ghi `applied_to_version: "{new_version}"` ở root level của findings (xem "Chọn full vs delta").
|
|
897
|
+
**`{changelog_scope}` dựng theo đúng 3 bước ở Phase 3 của `--fix`** — gom theo `uc_id`, mỗi nhóm một mệnh đề `{uc_id}: {mô tả}`, `uc_id: ""` → `PRD-global`. Ở Resume Mode phần lớn finding là loại **con người quyết** nên **đổi hành vi** — chỉ gắn `[no-behavior]` cho nhóm thuần cấu trúc (P4). **BR/AC phải đi KÈM UC sở hữu** (`UC3: sửa BR8`), không bao giờ đứng một mình: consumer khớp theo UC, nên `sửa BR8` trơ trọi làm UC3 bị xếp ⓘ trong khi BR8 vừa đổi (G53).
|
|
866
898
|
|
|
867
899
|
**Với finding BDD:**
|
|
868
900
|
| check_id | Làm gì |
|
|
@@ -892,6 +924,9 @@ Changes:
|
|
|
892
924
|
- {tóm tắt change 2}
|
|
893
925
|
|
|
894
926
|
{If PRD}: Version bumped: {old} → {new} | Status: reset về draft (cần duyệt lại)
|
|
927
|
+
{If PRD}: Changelog : | {new} | {today} | {changelog_scope} |
|
|
928
|
+
↳ UC sẽ hiện 🟠 PRD_DRIFT: {UC5} · UC ở lại ⓘ STALE_REF: {UC1-4, UC6-8}
|
|
929
|
+
(nhóm [no-behavior] và UC không đụng → KHÔNG cần /generate-bdd)
|
|
895
930
|
{If BDD}: bdd_version: {old} → {new} | @trace.status: reset về draft (cần duyệt lại)
|
|
896
931
|
{If BDD, chỉ khi có ≥1 SC bump}: sc_version: {UC-ID}-SC2 1.0→1.1, {UC-ID}-SC5 1.2→1.3
|
|
897
932
|
↳ {n} SC này sẽ hiện DRIFT ở /validate-traces → /generate-code {feature-file} để sinh lại
|