@educa-corp/sdd-framework 0.6.0 → 0.7.0
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 +391 -30
- package/core/FRAMEWORK_VERSION +1 -1
- package/{commands/extend-prd.md → core/commands/amend-prd.md} +205 -173
- package/core/commands/dev-run-test.md +47 -9
- package/core/commands/extend-prd.md +39 -12
- package/core/commands/generate-bdd.md +43 -4
- package/core/commands/generate-code.md +33 -0
- package/core/commands/generate-tech-docs.md +34 -2
- 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 +284 -11
- package/core/rules/workflow.md +34 -0
- package/core/steps/context-loader.md +26 -5
- package/core/templates/feature.template +1 -1
- package/docs/02-concepts/architecture.md +36 -0
- package/docs/04-reference/commands.md +148 -134
- package/docs/04-reference/trace-schema.md +39 -0
- package/docs/explain/02b-extend-prd.md +1 -1
- package/docs/explain/02c-amend-prd.md +152 -0
- 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`
|
|
@@ -375,9 +375,37 @@ Chỉ cần kiểm tra trạng thái đã phân giải:
|
|
|
375
375
|
| `active_service` đã phân giải thành path service | Tiếp tục với `active_module` đã set. |
|
|
376
376
|
| `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
377
|
| `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 = "
|
|
378
|
+
| `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. |
|
|
379
|
+
| `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
380
|
| Single-service (không có section `services`) | `active_module = tech_stack.module` (đã set ở Bước 6.5). Tiếp tục. |
|
|
380
381
|
|
|
382
|
+
#### `unrouted` — vì sao KHÔNG chặn ở đây *(G51)*
|
|
383
|
+
|
|
384
|
+
PRD và BDD là artifact **nghiệp vụ**. PO biết `domain` (auth, payment) và biết `platform`
|
|
385
|
+
(*"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,
|
|
386
|
+
và ở feature đầu tiên của một domain mới thì **chưa ai quyết**.
|
|
387
|
+
|
|
388
|
+
Chặn BDD vì lý do đó là đặt cổng **sai phase**: nó chặn phase KHÔNG CẦN biết, trong khi
|
|
389
|
+
`/generate-code` — phase **buộc phải** biết mới ghi được file — mới là chỗ đúng để chặn.
|
|
390
|
+
|
|
391
|
+
**Việc cần làm khi `unrouted`:**
|
|
392
|
+
1. `@trace.service: unrouted` vào header `.feature` (đừng để trống — cột 23 sẽ mất thông tin)
|
|
393
|
+
2. **`active_module` chưa biết** ⇒ hỏi người dùng `platform` trực tiếp (`web`/`app`/`system`) thay
|
|
394
|
+
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:
|
|
395
|
+
`web` → *clicks* · `app` → *taps* · `system` → *calls the API*.
|
|
396
|
+
3. In ⚠️ vào report:
|
|
397
|
+
```
|
|
398
|
+
⚠️ service: unrouted — chưa có mapping cho domain "{domain}"{ platform "{platform}"} trong
|
|
399
|
+
services: của project-context.yaml.
|
|
400
|
+
BDD đã sinh xong và ĐÚNG — đây là việc của architect, không phải của bạn.
|
|
401
|
+
Architect thêm mapping → /validate-traces tự nâng unrouted → path, KHÔNG cần chạy lại lệnh này.
|
|
402
|
+
/generate-code sẽ DỪNG cho tới khi có mapping (nó cần biết ghi vào repo nào).
|
|
403
|
+
```
|
|
404
|
+
|
|
405
|
+
> **Vì sao không cần chạy lại `/generate-bdd`:** `/validate-traces` đọc lại `services:` **mỗi lần
|
|
406
|
+
> chạy** và nâng `unrouted` → path khi mapping xuất hiện — cùng cách nó đã làm với `spec_ver`.
|
|
407
|
+
> Sổ **tự lành**.
|
|
408
|
+
|
|
381
409
|
### Phân giải `active_platform` (umbrella mode)
|
|
382
410
|
|
|
383
411
|
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`.
|
|
@@ -505,7 +533,18 @@ Trước khi sinh, kiểm tra các file `.feature` có sẵn cho PRD này:
|
|
|
505
533
|
F — gen lại toàn bộ scenario
|
|
506
534
|
N — huỷ
|
|
507
535
|
```
|
|
508
|
-
3. Tiếp tục theo lựa chọn của người dùng
|
|
536
|
+
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 ⓘ)*:
|
|
537
|
+
|
|
538
|
+
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:
|
|
539
|
+
|
|
540
|
+
| Tình trạng row trong khoảng | Khuyến nghị |
|
|
541
|
+
|---|---|
|
|
542
|
+
| **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 |
|
|
543
|
+
| UC của target **có** trong `affected_ucs` | **Y** — cập nhật đúng scenario của UC đó |
|
|
544
|
+
| 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 |
|
|
545
|
+
| 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 |
|
|
546
|
+
|
|
547
|
+
> **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
548
|
|
|
510
549
|
---
|
|
511
550
|
|
|
@@ -602,7 +641,7 @@ Với mỗi UC, ghi vào path trên và set `# @trace.platform: {active_platform
|
|
|
602
641
|
# @trace.revision: 1 ← field tĩnh; version theo dõi bằng @trace.bdd_version
|
|
603
642
|
# @trace.domain: <domain>
|
|
604
643
|
# @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: {
|
|
644
|
+
# @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
645
|
# @trace.module: {active_module trong umbrella mode; "unknown" trong spec repo mode}
|
|
607
646
|
# @trace.status: draft
|
|
608
647
|
# @trace.author: AI-generated
|
|
@@ -816,7 +855,7 @@ sc_id\tsc_title\tspec_ver\tgen_ver\timplemented_by\ttest_count\ttest_classes\tde
|
|
|
816
855
|
| `fe_phase` | `—` (set bởi `/generate-code --phase` khi FE implement) |
|
|
817
856
|
| `status` | `UNTRACKED` |
|
|
818
857
|
| `last_updated` | hôm nay `YYYY-MM-DD` |
|
|
819
|
-
| `service` | `@trace.service` từ header `.feature` — đội/submodule sở hữu scenario này. `
|
|
858
|
+
| `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
859
|
| `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
860
|
|
|
822
861
|
## 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.
|
|
@@ -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
|
════════════════════════════════════════════════════════════════════════════
|
|
@@ -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
|
package/core/commands/sync.md
CHANGED
|
@@ -180,6 +180,90 @@ Nếu người đọc là PO/Dev, thêm một dòng nudge:
|
|
|
180
180
|
|
|
181
181
|
---
|
|
182
182
|
|
|
183
|
+
## Step 1e — Spec delta: **tài liệu nào vừa đổi** *(hai mốc, hai câu hỏi khác nhau)*
|
|
184
|
+
|
|
185
|
+
*Câu hỏi số MỘT của dev sau mỗi lần sync là "tài liệu của phần tôi đang làm có đổi không?". Step này trả lời nó. Range `{old_sha}..{new_sha}` đã thu ở Step 1c — không phát sinh fetch.*
|
|
186
|
+
|
|
187
|
+
> **Vì sao step này tồn tại (GAPS-v4 G56).** Bản cũ diff **đúng ba** đường dẫn ở Step 1d —
|
|
188
|
+
> `feedback/bug-reports/`, `feedback/bdd-proposals/`, `feedback/prd-change-requests/` — và
|
|
189
|
+
> `specs/` **không có trong danh sách**. Tức `/sync` hỏi *"có góp ý gì mới không"* (đúng và hữu ích)
|
|
190
|
+
> rồi bỏ qua **chính tài liệu mà mọi lệnh downstream đọc**: PRD · BDD · tech-doc · design-spec.
|
|
191
|
+
>
|
|
192
|
+
> Nó **đang cầm sẵn câu trả lời**: Step 1c vừa thu cả hai đầu SHA, và Step 1d đã chạy một `git diff`.
|
|
193
|
+
> Thêm `specs/` là thêm **một tham số đường dẫn**.
|
|
194
|
+
>
|
|
195
|
+
> Thay vào đó, dòng `Next` in cứng `/validate-traces (full coverage check)` — **y hệt nhau** dù 0 file
|
|
196
|
+
> đổi hay 12 file đổi. Một lời nhắc không bao giờ thay đổi thì **không mang thông tin**, nên bị lướt.
|
|
197
|
+
> Đây đúng lập luận `gate.md` Bước 3b dùng để cắt CHECKPOINT xuống hai dòng khi mọi thứ sạch —
|
|
198
|
+
> *"cổng luôn in ra một bảng giống hệt nhau … nên `Y` thành phản xạ và cổng hỏng âm thầm"*. Nguyên
|
|
199
|
+
> tắc đó đã áp cho `gate`; đây là chỗ nó còn thiếu.
|
|
200
|
+
>
|
|
201
|
+
> Và tệ hơn: lệnh duy nhất được gợi ý là lệnh **đắt nhất** (quét cả repo). Nên con đường duy nhất
|
|
202
|
+
> được chỉ là con đường người ta sẽ không đi. Step này làm nó **có scope**.
|
|
203
|
+
>
|
|
204
|
+
> **Đây KHÔNG phải một detector bị hỏng** — mọi detector đều hoạt động đúng. Đây là một **công tắc
|
|
205
|
+
> bị thiếu**: không ai biết là cần bật.
|
|
206
|
+
|
|
207
|
+
Bỏ qua **im lặng** nếu `{paths.specs_dir}` không tồn tại trong REPO (chọn REPO + range theo đúng quy tắc Step 1d).
|
|
208
|
+
|
|
209
|
+
### 1e-A — Đổi gì kể từ lần **PULL** trước
|
|
210
|
+
|
|
211
|
+
```bash
|
|
212
|
+
git -C {REPO} diff --name-status {old_sha}..{new_sha} -- specs/
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
Nhóm kết quả theo **feature-package** (`specs/{domain}/{prd-slug}/`), và với mỗi file đổi, đọc **nhãn version ở hai đầu** — thứ dev cần không phải tên file mà là *nhãn đã nhảy chưa*:
|
|
216
|
+
|
|
217
|
+
| Loại file | Nhãn đọc ở đâu | Bản cũ đọc bằng |
|
|
218
|
+
|---|---|---|
|
|
219
|
+
| PRD (`.md` ở gốc package) | Metadata `\| **Version** \|` + row `# Change Log` đầu bảng | `git -C {REPO} show {old_sha}:{path}` |
|
|
220
|
+
| `.feature` | `# @trace.bdd_version` | như trên |
|
|
221
|
+
| `tech-docs/*-tech-design.md` | `@trace.revision` | như trên |
|
|
222
|
+
| `design-spec/*.md` | `\| **Version** \|` | như trên |
|
|
223
|
+
|
|
224
|
+
**Cap có công bố:** > **20** file đổi → **bỏ** phần đọc nhãn (mỗi file là một `git show`), chỉ liệt kê package + số file, và **in rõ là đã cap**:
|
|
225
|
+
`ⓘ {n} file đổi (> 20) — bỏ phần so nhãn version để không làm chậm sync. Chạy /validate-traces để có bản đầy đủ.`
|
|
226
|
+
*(Luật framework: cap thì phải nói ra. Một giới hạn im lặng đọc như "đã phủ hết" trong khi không phải.)*
|
|
227
|
+
|
|
228
|
+
### 1e-B — Đổi gì kể từ lần **AUDIT** gần nhất ⭐
|
|
229
|
+
|
|
230
|
+
*Đây là phần 1e-A **không** trả lời được, và là câu hỏi đúng hơn.*
|
|
231
|
+
|
|
232
|
+
Diff `{old_sha}..{new_sha}` **reset mỗi lần pull**. Pull thứ Hai, thứ Ba, thứ Tư mà không audit lần nào → đến thứ Năm cái thấy được chỉ là delta của **một ngày**, không phải nợ đã tích.
|
|
233
|
+
|
|
234
|
+
Đọc mốc **`spec_baseline`** trong `{living_docs_dir}/trace-report.json` — khối do `/validate-traces` Step 6b ghi (contract: `bin/trace-schema.json` → `spec_edit_detection`). Mỗi entry: `prd_path` · `sha_at_audit` · `version_at_audit`.
|
|
235
|
+
|
|
236
|
+
*Phân giải `living_docs_dir` bằng đúng quy tắc một dòng của Step 5: `{spec_source}/.living-docs` nếu `setup.spec_source` được set, else `.living-docs` ở gốc.*
|
|
237
|
+
|
|
238
|
+
Với mỗi PRD có entry: so `Version` **hiện tại** với `version_at_audit`.
|
|
239
|
+
|
|
240
|
+
| Điều kiện | In gì |
|
|
241
|
+
|---|---|
|
|
242
|
+
| Khác nhau | PRD này đã đổi kể từ lần audit — vào danh sách ⚠️ |
|
|
243
|
+
| Bằng nhau | Bỏ qua *(và `/validate-traces` Step 3.9 sẽ lo ca "nội dung đổi mà nhãn không đổi" — không phải việc của step này)* |
|
|
244
|
+
| Không có `trace-report.json`, hoặc khối `spec_baseline` vắng | In `ⓘ Chưa có mốc audit — chạy /validate-traces một lần để Step 1e-B có hiệu lực từ lần sau.` rồi bỏ qua |
|
|
245
|
+
|
|
246
|
+
**KHÔNG ghi gì cả.** Step này chỉ **đọc** mốc; chủ sở hữu của `spec_baseline` là `/validate-traces` Step 6b. `/sync` ghi mốc sẽ làm mốc audit trượt theo mỗi lần pull — tức phá đúng thứ nó đang dùng.
|
|
247
|
+
|
|
248
|
+
### Xuất
|
|
249
|
+
|
|
250
|
+
```
|
|
251
|
+
📄 Spec đã đổi (pulled this sync):
|
|
252
|
+
payment/create-invoice PRD v1.2 → v1.4
|
|
253
|
+
changelog: UC2: sửa BR5; UC7 mới
|
|
254
|
+
bdd/web/PAY01-UC2.feature (bdd_version 1.3 → 1.4)
|
|
255
|
+
user/create-account tech-docs/USR01-tech-design.md (revision 3 → 4)
|
|
256
|
+
(hoặc: 📄 Spec: không đổi trong lần pull này)
|
|
257
|
+
|
|
258
|
+
⚠️ 3 PRD đã đổi kể từ lần /validate-traces gần nhất (KHÔNG chỉ lần pull này):
|
|
259
|
+
payment/create-invoice audit tại v1.2 · giờ v1.4
|
|
260
|
+
user/create-account audit tại v2.0 · giờ v2.1
|
|
261
|
+
order/bulk-export audit tại v1.0 · giờ v1.3
|
|
262
|
+
→ /validate-traces {các PRD trên}
|
|
263
|
+
(hoặc: ✅ Mọi PRD đã được audit ở version hiện tại)
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
---
|
|
183
267
|
## Step 2 — Post-sync State Check
|
|
184
268
|
|
|
185
269
|
Chạy `git status --short` và kiểm tra entry submodule bị modified (dòng bắt đầu bằng ` M` mà path khớp một submodule).
|
|
@@ -396,6 +480,22 @@ Umbrella state
|
|
|
396
480
|
⚠️ Pointer changed: git add {spec_source} && git commit -m "chore: sync specs"
|
|
397
481
|
(or: ✅ Clean — no commit needed)
|
|
398
482
|
|
|
483
|
+
Spec đã đổi (pulled this sync) ← Step 1e-A
|
|
484
|
+
📄 payment/create-invoice PRD v1.2 → v1.4
|
|
485
|
+
changelog: UC2: sửa BR5; UC7 mới
|
|
486
|
+
bdd/web/PAY01-UC2.feature (bdd_version 1.3 → 1.4)
|
|
487
|
+
user/create-account tech-docs/USR01-tech-design.md (revision 3 → 4)
|
|
488
|
+
(hoặc: 📄 Spec: không đổi trong lần pull này)
|
|
489
|
+
(hoặc: ⓘ 34 file đổi (> 20) — đã bỏ phần so nhãn version cho nhanh)
|
|
490
|
+
|
|
491
|
+
Nợ audit đã tích (KHÔNG chỉ lần pull này) ← Step 1e-B
|
|
492
|
+
⚠️ 3 PRD đã đổi kể từ lần /validate-traces gần nhất:
|
|
493
|
+
payment/create-invoice audit tại v1.2 · giờ v1.4
|
|
494
|
+
user/create-account audit tại v2.0 · giờ v2.1
|
|
495
|
+
order/bulk-export audit tại v1.0 · giờ v1.3
|
|
496
|
+
(hoặc: ✅ Mọi PRD đã được audit ở version hiện tại)
|
|
497
|
+
(hoặc: ⓘ Chưa có mốc audit — chạy /validate-traces một lần để có hiệu lực từ lần sau)
|
|
498
|
+
|
|
399
499
|
Tester feedback (pulled this sync)
|
|
400
500
|
📥 1 bug report: BUG-20260608-01 FT-001 [Code]
|
|
401
501
|
1 proposal: FT-001-trailing-spaces → AC2 (pending review)
|
|
@@ -426,5 +526,9 @@ Spec Manifest
|
|
|
426
526
|
---
|
|
427
527
|
Status : ✅ Complete | ⚠️ Warnings
|
|
428
528
|
Output Artifacts: updated .trace-mirror/ (panel mirror), spec-manifest.yaml
|
|
429
|
-
|
|
529
|
+
(Step 1e chỉ ĐỌC — nó không bao giờ ghi spec_baseline; chủ sở hữu là /validate-traces Step 6b)
|
|
530
|
+
Next : {phụ thuộc kết quả Step 1e — KHÔNG in một hằng số}
|
|
531
|
+
• có PRD trong danh sách 1e-B → /validate-traces {các PRD đó}
|
|
532
|
+
• 1e-B sạch, 1e-A có đổi → /generate-code {UC-ID} cho phần vừa đổi
|
|
533
|
+
• cả hai sạch → ✅ Spec khớp audit — không cần audit lại
|
|
430
534
|
```
|