# /generate-spec-manifest — Sinh Spec Manifest cho External Agent

Quét tất cả file spec và ghi một `spec-manifest.yaml` ở project root.
File này dành cho **external agent** (vd agent của tester) — nó không commit vào git.

## Gate

{{include:steps/gate.md}}

*Lưu ý: Với lệnh này, không có target file — nó quét cả dự án. Bỏ qua `$ARGUMENTS` trừ khi truyền domain filter.*

## Context

{{include:steps/context-loader.md}}

---

## Process

### Step 1 — Xác định scan root

Đọc `project-context.yaml` để xác định mode và path:

**Umbrella mode** (`setup.mode: umbrella`):
```
spec_root      = {setup.spec_source}              ← spec submodule của PO
prd_glob       = {spec_root}/specs/*/*/*.md           ← file .md ở gốc feature folder = PRD ({TICKET-ID}-{prd-slug}.md)
pdd_glob       = {spec_root}/specs/product-definition/**/*.md
services       = {services}                        ← map domain → paths
```

**Single-service mode** (không có `setup.mode`):
```
spec_root      = .
prd_glob       = {paths.specs_dir}/*/*/*.md           ← file .md ở gốc feature folder = PRD ({TICKET-ID}-{prd-slug}.md)
pdd_glob       = {paths.product_definitions_dir}/**/*.md
services       = { default: { specs_dir: {paths.specs_dir}, tech_docs_dir: {paths.tech_docs_dir} } }
```

Nếu truyền domain filter trong `$ARGUMENTS` → chỉ quét PRD khớp domain đó.

---

### Step 2 — Quét file PRD

Với mỗi file `.md` khớp `prd_glob`:

1. Đọc bảng metadata của file:
   - `TICKET-ID` từ `| **PRD ID** |`
   - `domain` từ `| **Domain** |`
   - `status` từ `| **Status** |`
   - `version` từ `| **Version** |`
2. Cũng đọc frontmatter `@trace.domain` nếu có (dùng cái này thay vì domain bảng metadata nếu cả hai tồn tại)
3. Ghi: `{ ticket_id, domain, status, version, prd_path }` — path tương đối với manifest root

Skip file không xác định được `TICKET-ID`.

---

### Step 3 — Khớp file PDD

Với mỗi TICKET-ID tìm thấy ở Step 2:

Tìm `pdd_glob` một file có tên chứa TICKET-ID (vd `FT-001-*.md`).
- Tìm thấy → ghi `pdd_path` (tương đối với manifest root)
- Không thấy → ghi `pdd: null`

---

### Step 4 — Khớp file BDD và Tech-Doc theo từng service

Với mỗi TICKET-ID, với mỗi service trong map `services`:

**BDD:**
- Glob `{service.specs_dir}/**/{TICKET-ID}*.feature`
- Cũng kiểm tra file chứa `@trace.prd: {TICKET-ID}` trong frontmatter nếu glob không trả gì
- Tìm thấy → ghi path dưới `bdd.{service_key}`
- Không thấy → bỏ key (đừng ghi `null` cho service chưa có BDD)

**Tech-docs:**
- Glob `{service.tech_docs_dir}/**/{TICKET-ID}*.md`
- Cũng kiểm tra file chứa `@trace.prd: {TICKET-ID}` nếu glob không trả gì
- Tìm thấy → ghi path dưới `tech_docs.{service_key}`
- Không thấy → bỏ key

Mọi path tương đối với manifest root (umbrella root hoặc project root).

---

### Step 5 — Ghi spec-manifest.yaml

Ghi vào `{manifest_root}/spec-manifest.yaml` (ghi đè nếu tồn tại).

Format:

```yaml
# Auto-generated by /generate-spec-manifest — DO NOT edit manually
# To regenerate: /generate-spec-manifest
# This file is excluded from git — see .gitignore

version: "1.0"
generated_at: "{YYYY-MM-DD}"
project_mode: "{umbrella | single}"

features:
  {TICKET-ID}:
    domain: {domain}
    status: {status}
    prd_version: "{version}"
    prd: "{prd_path}"
    pdd: "{pdd_path}"               # omit if null
    tech_docs:
      {service_key}: "{path}"       # only include services where file was found
    bdd:
      {service_key}: "{path}"       # only include services where file was found
```

Sort features theo TICKET-ID alphabet.
Bỏ hẳn block `tech_docs` nếu không tìm thấy tech-doc cho service nào.
Bỏ hẳn block `bdd` nếu không tìm thấy BDD cho service nào.

---

### Step 6 — Đảm bảo .gitignore

Kiểm tra `{manifest_root}/.gitignore`:
- Nếu `spec-manifest.yaml` đã được liệt kê → không làm gì
- Nếu chưa → append vào `.gitignore`:

```
# Auto-generated — do not commit
spec-manifest.yaml
```

In: `✅ spec-manifest.yaml added to .gitignore`

---

## Output

{{include:steps/report-footer.md}}

```
/generate-spec-manifest Hoàn tất
---
Status  : ✅ Complete
Output  : spec-manifest.yaml  ({N} features)
Mode    : {umbrella | single}
.gitignore : ✅ spec-manifest.yaml excluded

Summary:
  {N} PRD scanned  ({A} approved, {D} draft)
  {N} PDD matched
  {N} BDD file matched  (across {S} services)
  {N} Tech-doc file matched  (across {S} services)

  ⚠️  {N} PRD không có BDD khớp:
    - {TICKET-ID} ({domain}) — chạy /generate-bdd trước
  ⚠️  {N} PRD không có tech-docs khớp:
    - {TICKET-ID} ({domain}) — chạy /generate-tech-docs trước

Next   : Chia sẻ path spec-manifest.yaml với tester agent
         Sinh lại bất cứ lúc nào: /generate-spec-manifest
```
