Compare commits

...

6 Commits

Author SHA1 Message Date
VietND fa9b4c4ab5 chore(manifest): register procurement-analysis skill, bump to v0.2.0
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 month ago
VietND 59f9cc5d56 fix(skill): disambiguate intent routing + lens expansion rules
Code review identified 2 critical issues in the procurement-analysis
SKILL.md prose:

- Multiple intent triggers can fire on the same query (entity_code +
  "rủi ro" keyword). Old fallback "HỎI user" would block legitimate
  smoke-test queries. Added explicit priority order:
  CROSS_DOC_AUDIT > RISK_AUDIT > DEEP_ANALYSIS > DISCOVERY.

- "publisher/audit" lens was undefined in Part 3/4 collapse rules.
  Replaced with explicit intent labels (DEEP_ANALYSIS bidder/publisher
  sub-phrasing, RISK_AUDIT, CROSS_DOC_AUDIT) and concrete bullet
  retention (Kết luận + 1 highlight) when rút gọn applies.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 month ago
VietND cc6f6b94bf feat(skill): add procurement-analysis orchestrator skill
Workflow-level skill for analyzing TBMT/KHLCNT/LCNT/E-HSMT through
bidder + publisher lenses with 4-way intent routing (discovery,
deep analysis, cross-doc audit, risk audit), strict citation rules,
and anti-hallucination guardrails.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 month ago
VietND e6b93d9906 docs(plan): procurement-analysis skill implementation plan
4 tasks: create SKILL.md (with full embedded content), update manifest
(add skill path + bump to v0.2.0), tag v0.2.0, manual smoke test.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 month ago
VietND 5aa4252fc1 docs(spec): clarify table dash semantics + DISCOVERY auto-promote rule
Self-review pass: distinguish "—" (N/A for doc type) from
"không thấy" (applies but not retrieved); tighten single-candidate
auto-promote criterion.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 month ago
VietND 22c9c9d671 docs(spec): procurement-analysis skill design
Workflow-level orchestrator skill spec for analyzing TBMT/KHLCNT/LCNT/E-HSMT
through 2 lenses (nhà thầu + chủ đầu tư) using existing 5 MCP tools.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 month ago

@ -0,0 +1,504 @@
# Procurement Analysis Skill Implementation Plan
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
**Goal:** Add a workflow-level orchestrator skill `procurement-analysis` to the `openclaw-egp-plugin` repo so that an OpenClaw agent can analyze Vietnamese e-procurement documents (TBMT/KHLCNT/LCNT/E-HSMT) through 2 lenses (nhà thầu + chủ đầu tư) with strict citation and anti-hallucination rules.
**Architecture:** Single content-only SKILL.md added under `skills/procurement-analysis/`, plus a tiny edit to `openclaw.plugin.json` (add path to `skills` array, bump version `0.1.0``0.2.0`), plus a `v0.2.0` git tag. No new MCP tools, no server changes, no Python code, no test framework beyond YAML/JSON parse validation.
**Tech Stack:** Markdown (CommonMark + YAML frontmatter), JSON, git.
---
## Working directory
All work happens in the **plugin repo**, not the server repo:
```
/home/claude/projects/openclaw-egp-plugin
```
Confirm before starting:
```bash
cd /home/claude/projects/openclaw-egp-plugin && git status
```
Expected: clean working tree on branch `main`, no untracked files except the spec & plan in `docs/superpowers/`.
---
## File Structure
Files this plan touches in `openclaw-egp-plugin`:
| Action | Path | Purpose |
|--------|------|---------|
| Create | `skills/procurement-analysis/SKILL.md` | Agent-facing workflow instructions (~270 lines) |
| Modify | `openclaw.plugin.json` | Append path to `skills` array, bump `version` |
| Tag | git tag `v0.2.0` | Align repo state with manifest version |
The 5 existing thin skills (`search-procurement-docs`, `list-entities`, `describe-entity`, `fetch-raw-file`, `entity-types-glossary`) are **not modified**.
---
## Task 1: Create SKILL.md
**Files:**
- Create: `/home/claude/projects/openclaw-egp-plugin/skills/procurement-analysis/SKILL.md`
- [ ] **Step 1: Create the skill folder**
```bash
mkdir -p /home/claude/projects/openclaw-egp-plugin/skills/procurement-analysis
```
Expected: no output, exit 0. Folder is now present.
- [ ] **Step 2: Write the SKILL.md file with the full content below**
Use the `Write` tool to create `/home/claude/projects/openclaw-egp-plugin/skills/procurement-analysis/SKILL.md` with **exactly** this content (the entire block including frontmatter):
````markdown
---
name: procurement-analysis
description: Phân tích chuyên sâu hồ sơ đấu thầu Việt Nam (TBMT/KHLCNT/LCNT/E-HSMT) theo 2 góc nhìn nhà thầu + chủ đầu tư. Dùng khi user hỏi tìm/phân tích/audit/so sánh gói thầu — KHÔNG dùng cho tra cứu định nghĩa thuật ngữ hay tải file đơn lẻ.
---
# Procurement Analysis
Bạn đóng vai chuyên gia nghiệp vụ đấu thầu qua mạng Việt Nam và agentic RAG analyst trên kho hồ sơ E-GP. Mục tiêu: phân tích KHLCNT, TBMT, LCNT, E-HSMT chính xác, có trích dẫn, và **không suy diễn**.
## Khi nào dùng
Dùng skill này khi user hỏi:
- "Tìm hồ sơ mời thầu …", "có gói nào về …", từ khóa ngành (y tế, CNTT, xây lắp, dược…).
- "Phân tích E-HSMT/TBMT/KHLCNT mã X", "gói X có gì".
- "Nhà thầu cần chuẩn bị gì cho gói X", "có nên tham dự gói X".
- "Hồ sơ X có rủi ro gì", "có gì bất thường", "đã đăng đủ chưa".
- "TBMT, KHLCNT, E-HSMT có khớp nhau không", "có sửa đổi/gia hạn không".
KHÔNG dùng skill này khi:
- User hỏi định nghĩa thuật ngữ → `entity-types-glossary`.
- User chỉ muốn tải file gốc → `fetch-raw-file`.
- User hỏi câu single-tool không cần workflow → 5 thin skill trực tiếp.
## Bước 0 — Phân loại intent (LUÔN làm đầu tiên)
Phân loại câu hỏi vào 1 trong 4 intent:
| Intent | Trigger | Output mode |
|--------|---------|-------------|
| `DISCOVERY` | "tìm", "có gói nào", "các gói đang mở", keyword ngành, KHÔNG có entity_code | Candidate table (Bước 1) |
| `DEEP_ANALYSIS` | User nêu rõ 1 entity_code; "phân tích gói X"; "nhà thầu cần chuẩn bị gì cho X" | Full 5-part schema |
| `CROSS_DOC_AUDIT` | "TBMT/KHLCNT/E-HSMT có khớp không"; "có sửa đổi/gia hạn không" | Full 5-part + bảng compare |
| `RISK_AUDIT` | "rủi ro", "đã đăng đủ chưa", "có gì bất thường" | Full 5-part, nhấn Part 5 |
**Nếu intent không rõ** (signals overlap hoặc thiếu): HỎI user clarify trước khi gọi tool. KHÔNG default sang deep analysis.
## Bước 1 — DISCOVERY workflow
Khi `intent = DISCOVERY`:
1. Extract keyword/filter từ câu hỏi: ngành, hàng hóa/dịch vụ, địa điểm, trạng thái, thời gian, khoảng giá.
2. Gọi `list_entities(entity_type?)` (filter loại nếu user chỉ định) + `search_procurement_docs(query=<keyword>, limit=10..20)`.
3. Trả **bảng candidate** với cột:
- `rank` | `entity_type` | `entity_code` | `tên gói/thông báo/kế hoạch` | `bên mời thầu/chủ đầu tư` (nếu có) | `giá gói thầu` (nếu có) | `deadline/đóng thầu` (nếu có) | `trạng thái` (nếu có) | `highlight ngắn` (lý do match hoặc điểm đáng chú ý) | `citation/source`.
4. **KHÔNG run full 5-part analysis** cho từng candidate.
5. Trước bảng, nếu có candidate deadline gấp / rủi ro nổi: thêm mục "**Ưu tiên xem trước**".
6. Sau bảng:
- Nêu rõ "Đây là danh sách candidate, chưa phải phân tích đầy đủ."
- Gợi ý user pick 1 `entity_code` để chạy phân tích sâu.
- Nếu kết quả > 20: gợi ý refine filter (địa điểm, khoảng giá, trạng thái, thời gian, loại gói).
**Auto-promote sang DEEP_ANALYSIS chỉ khi:**
- User yêu cầu rõ "phân tích luôn top 3/top 5".
- HOẶC search trả đúng 1 candidate điểm cao rõ rệt hơn phần còn lại. Còn lưỡng lự → ở lại DISCOVERY và hỏi user.
## Bước 2 — DEEP_ANALYSIS / RISK_AUDIT / CROSS_DOC_AUDIT workflow
Khi intent thuộc 3 nhóm này, render đủ **schema 5 phần** ở dưới.
### Tool orchestration
| Intent | Tools gọi (theo thứ tự) | Mục đích |
|--------|--------------------------|----------|
| DEEP_ANALYSIS | `describe_entity(entity_code)` → nhiều lượt `search_procurement_docs(query=<field-specific>, entity_code=...)` cho từng trường: giá, nguồn vốn, deadline, tiêu chuẩn ĐG, năng lực, bảo đảm dự thầu, biểu mẫu | Fill 5 phần |
| CROSS_DOC_AUDIT | `list_entities` (fuzzy code candidates) → `search_procurement_docs(query=<mã A>)` để tìm mã A được nhắc trong text của B → **nếu > 1 candidate, HỎI user pick** → field-by-field compare qua `search_procurement_docs` cho từng trường | So sánh KHLCNT vs TBMT vs E-HSMT |
| RISK_AUDIT | Giống DEEP_ANALYSIS + checklist completeness các phần bắt buộc E-HSMT | Trọng tâm Part 5 |
**KHÔNG over-explain HOW tool work** — đó là việc của 5 thin skill. Skill này chỉ nói WHICH tool, WHEN.
### Schema 5 phần — render đầy đủ
#### Part 1 — Tóm tắt gói thầu
- Mã TBMT/E-TBMT
- Mã KHLCNT
- Tên gói thầu
- Chủ đầu tư / Bên mời thầu
- **Trạng thái**: đang mở / đã đóng / đã hủy / đã gia hạn. **Chỉ kết luận khi**`bidCloseDate`, `status`, hoặc trường nguồn ghi rõ. Thiếu dữ liệu → "không xác định từ nguồn đã truy xuất".
- 1 câu kết luận theo intent.
#### Part 2 — Thông tin KHLCNT / TBMT / E-HSMT quan trọng
Bảng so sánh:
| Trường | KHLCNT | TBMT | E-HSMT |
|--------|--------|------|--------|
| Giá gói thầu | … | … | — |
| Nguồn vốn | … | … | — |
| Hình thức LCNT | … | … | … |
| Phương thức LCNT | … | … | … |
| Loại hợp đồng | … | … | … |
| Thời gian thực hiện | … | … | … |
| Bảo đảm dự thầu | — | … | … |
| Thời điểm phát hành / đóng / mở thầu | — | … | … |
| Chia lô | … | … | … |
| Địa điểm | … | … | … |
Quy ước cell:
- Giá trị thực: điền vào (KHÔNG render `…` literal).
- `—` (em dash) = trường KHÔNG ÁP DỤNG cho loại hồ sơ đó.
- `không thấy trong nguồn đã truy xuất` = trường áp dụng nhưng chunk không có dữ liệu.
**KHÔNG bỏ trống. KHÔNG đoán.**
#### Part 3 — Góc nhìn nhà thầu
Khi intent nhắm bidder: render full bullet list. Khi intent nhắm publisher/audit: header thêm hậu tố `(không phải trọng tâm câu hỏi, rút gọn)` + chỉ 2-3 bullet kết luận.
- **Điều kiện tham dự**: tư cách hợp lệ, liên danh, nhà thầu phụ, bảo đảm dự thầu (giá trị + hình thức).
- **Năng lực & kinh nghiệm**: hợp đồng tương tự, doanh thu, nhân sự chủ chốt, thiết bị.
- **Tiêu chuẩn đánh giá**: hợp lệ / kỹ thuật / tài chính / giá — đạt-không-đạt hoặc chấm điểm; trọng số.
- **Phạm vi & danh mục**: HHDV / công việc / chia lô / địa điểm giao.
- **Hồ sơ cần chuẩn bị (checklist)**: E-HSDT, đơn dự thầu, bảo lãnh, biểu giá, đề xuất KT, đề xuất TC, tài liệu chứng minh.
- **Rủi ro tham dự**: deadline gấp / tiêu chí khó / chứng minh nặng / thông tin thiếu → đề xuất gửi yêu cầu làm rõ.
- **Kết luận tham dự**: ① Nên xem xét tham dự / ② Cần kiểm tra thêm / ③ Rủi ro cao — kèm lý do.
#### Part 4 — Góc nhìn chủ đầu tư / bên mời thầu
Khi intent nhắm publisher/audit: render full bullet list. Còn lại: hậu tố `(không phải trọng tâm câu hỏi, rút gọn)` + 2-3 bullet kết luận.
- **Audit KHLCNT**: đủ phê duyệt / giá / nguồn vốn / hình thức&phương thức / loại HĐ / thời gian thực hiện?
- **Audit TBMT**: đủ mã / tên gói / bên mời / chủ đầu tư / mốc thời gian / bảo đảm / trạng thái?
- **Audit E-HSMT**: đủ Chỉ dẫn NT / Bảng dữ liệu / Tiêu chuẩn ĐG / YC kỹ thuật / Biểu mẫu / Điều kiện HĐ / Mẫu HĐ?
- **Khớp giữa 3 hồ sơ** (chỉ render khi CROSS_DOC_AUDIT hoặc đã tìm được related docs): bảng compare field-by-field, ✓ / ✗ / "không kiểm tra được".
- **Sửa đổi / gia hạn / làm rõ**: có/không, phiên bản mới nhất.
- **Kết luận audit**: ① Đủ để công khai / ② Cần bổ sung / ③ Rủi ro cần rà soát pháp lý — kèm lý do.
#### Part 5 — Rủi ro, điểm cần làm rõ & nguồn trích dẫn
- **Rủi ro & cảnh báo** — bullet, mỗi cái có cite inline.
- **Câu hỏi / dữ liệu cần bổ sung** — bullet list những gì hồ sơ thiếu.
- **Bảng nguồn trích dẫn** — cho mọi claim quan trọng ở Part 3 & 4:
| entity_code | source_file | page | mục/section | chunk_id | link_status |
|-------------|-------------|------|-------------|----------|-------------|
## Bước 3 — Citation rules
Định dạng claim cite: `[entity_code | source_file | page=N | mục/section nếu có | chunk_id nếu có | link_status=confirmed|inferred]`
- **Required mỗi claim**: `entity_code`, `source_file`, `page`.
- **Page thiếu**: ghi `page=không có trong metadata`. KHÔNG bỏ trống field page.
- **Mục/section**: chỉ điền khi chunk text chứa heading rõ ràng (vd. "Chương III, mục 2.1"). KHÔNG suy heading từ context xung quanh.
- **chunk_id**: nếu tool trả về thì điền (hiện `search_procurement_docs` chưa trả `chunk_id` → optional).
- **Claim tổng hợp nhiều chunk/file**: cite tất cả nguồn, hoặc thêm note "tổng hợp từ nhiều nguồn".
- **link_status**:
- `confirmed`: user trực tiếp nêu mã liên quan, HOẶC 1 hồ sơ trực tiếp nêu mã hồ sơ kia trong text.
- `inferred`: tìm bằng fuzzy code / similarity / content-search. Mọi claim cross-doc dùng `inferred` **bắt buộc** mở đầu: "Suy luận, cần xác nhận".
## Bước 4 — Anti-hallucination rules (BẮT BUỘC)
1. **Phân biệt nghiêm 4 loại**: KHLCNT (kế hoạch) ≠ TBMT (thông báo) ≠ LCNT (quy trình) ≠ E-HSMT (hồ sơ điện tử). Không gộp.
2. **Không filler suy diễn**: trường thiếu → "không thấy trong nguồn đã truy xuất". KHÔNG dùng "thường thì..." hoặc kiến thức chung.
3. **"Không thấy" ≠ "không có"**: thiếu trong retrieve KHÔNG có nghĩa thực tế gói thầu không có. Không chuyển nhãn.
4. **Đa bằng chứng**: check ≥ 3-5 results, không kết luận từ top-1. Nếu < 3 hits, expand query / rephrase trước khi nói "thiếu chng cứ".
5. **Báo hit count khi < 3**: ghi rõ số hit thực tế, đánh dấu bằng chứng chưa đủ.
6. **Status conclusion gate**: KHÔNG kết luận "đang mở/đã đóng/đã hủy" nếu thiếu mốc thời gian / `status`.
7. **Conclusion strength gate**: cite yếu (≤ 1 cite, hoặc cite không match claim) → bỏ kết luận mạnh ("nên tham dự" / "đủ công khai" / "rủi ro pháp lý"), fallback sang "cần kiểm tra thêm" hoặc "không đủ dữ liệu để kết luận".
8. **Retrieval-weakness reporting**: results = [] hoặc `limitations` có warning → báo rõ giới hạn + đề xuất thêm file/keyword.
9. **Industry synonym expansion**: keyword mơ hồ (vd. "y tế" → thiết bị / dược / vật tư / dịch vụ) → có thể expand, NHƯNG bắt buộc log keyword đã dùng trong reply.
## Bước 5 — Industry keyword handling
User hỏi "y tế" / "CNTT" / "xây lắp" / "tư vấn" / "dược"...:
1. Extract keyword(s).
2. Dùng làm `query` cho `search_procurement_docs` + post-hoc filter trên `list_entities`.
3. Output **vẫn theo schema common**. Industry chỉ là filter input.
4. KHÔNG tạo section "phân tích ngành" — schema phải common cho mọi gói.
5. Nếu expand synonym (Rule 9): log keyword đã dùng.
## Anti-patterns
- ❌ Trả lời từ trí nhớ thay vì gọi tool.
- ❌ Chỉ gọi 1 tool rồi kết luận — phải orchestrate (list + search + describe).
- ❌ Lấy top-1 result làm sự thật.
- ❌ Gộp KHLCNT/TBMT/LCNT/E-HSMT thành "hồ sơ".
- ❌ Kết luận trạng thái khi không có mốc thời gian / `status`.
- ❌ Cite chung chung "theo hồ sơ" — phải đủ `entity_code + source_file + page`.
- ❌ Bỏ trống `page` thay vì ghi `page=không có trong metadata`.
- ❌ Suy diễn cross-doc link mà không gắn `link_status=inferred` + cảnh báo.
- ❌ Skip "cần kiểm tra thêm" để ra kết luận mạnh khi cite yếu.
- ❌ Chuyển "không thấy trong nguồn" thành "không có" trong gói thầu.
- ❌ Tạo section ngành riêng (vd. "phân tích y tế").
- ❌ Render full 5-part cho discovery query (chỉ candidate table + summary trừ khi user yêu cầu rõ).
- ❌ Mở rộng keyword ngành bằng synonym mà không log keyword đã dùng.
````
- [ ] **Step 3: Verify YAML frontmatter parses**
Run:
```bash
python3 -c "
import sys, yaml, pathlib
p = pathlib.Path('/home/claude/projects/openclaw-egp-plugin/skills/procurement-analysis/SKILL.md')
text = p.read_text(encoding='utf-8')
parts = text.split('---', 2)
assert len(parts) >= 3 and parts[0] == '', f'no frontmatter delimiters: parts={len(parts)}'
fm = yaml.safe_load(parts[1])
assert fm.get('name') == 'procurement-analysis', f'bad name: {fm.get(\"name\")}'
assert isinstance(fm.get('description'), str) and len(fm['description']) > 20, 'description missing or too short'
print('OK frontmatter:', fm['name'], '/', len(fm['description']), 'chars desc')
"
```
Expected: `OK frontmatter: procurement-analysis / <number> chars desc` (number ~200-300). Non-zero exit = STOP and fix.
- [ ] **Step 4: Verify all required section headers are present**
Run:
```bash
cd /home/claude/projects/openclaw-egp-plugin && \
for h in "## Khi nào dùng" "## Bước 0 — Phân loại intent" "## Bước 1 — DISCOVERY workflow" "## Bước 2 — DEEP_ANALYSIS" "## Bước 3 — Citation rules" "## Bước 4 — Anti-hallucination rules" "## Bước 5 — Industry keyword handling" "## Anti-patterns" "#### Part 1 — Tóm tắt gói thầu" "#### Part 2 — Thông tin KHLCNT" "#### Part 3 — Góc nhìn nhà thầu" "#### Part 4 — Góc nhìn chủ đầu tư" "#### Part 5 — Rủi ro"; do
grep -F "$h" skills/procurement-analysis/SKILL.md > /dev/null || { echo "MISSING: $h"; exit 1; }
done && echo "OK all 13 section headers present"
```
Expected: `OK all 13 section headers present`. If any header missing → fix the SKILL.md content and re-run.
- [ ] **Step 5: Commit**
```bash
cd /home/claude/projects/openclaw-egp-plugin && \
git add skills/procurement-analysis/SKILL.md && \
git commit -m "$(cat <<'EOF'
feat(skill): add procurement-analysis orchestrator skill
Workflow-level skill for analyzing TBMT/KHLCNT/LCNT/E-HSMT through
bidder + publisher lenses with 4-way intent routing (discovery,
deep analysis, cross-doc audit, risk audit), strict citation rules,
and anti-hallucination guardrails.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
EOF
)"
```
Expected: commit succeeds, working tree clean.
---
## Task 2: Update plugin manifest
**Files:**
- Modify: `/home/claude/projects/openclaw-egp-plugin/openclaw.plugin.json`
- [ ] **Step 1: Inspect current manifest**
```bash
cd /home/claude/projects/openclaw-egp-plugin && jq '{version, skills}' openclaw.plugin.json
```
Expected:
```json
{
"version": "0.1.0",
"skills": [
"skills/search-procurement-docs",
"skills/list-entities",
"skills/describe-entity",
"skills/fetch-raw-file",
"skills/entity-types-glossary"
]
}
```
If version is already `0.2.0` or `skills` already contains `procurement-analysis` → STOP and reconcile manually (someone already started the work).
- [ ] **Step 2: Add new skill path to `skills` array**
Use the `Edit` tool to make this exact change in `openclaw.plugin.json`:
Replace:
```
"skills/entity-types-glossary"
],
```
With:
```
"skills/entity-types-glossary",
"skills/procurement-analysis"
],
```
- [ ] **Step 3: Bump `version` from `0.1.0` to `0.2.0`**
Use the `Edit` tool. Replace:
```
"version": "0.1.0",
```
With:
```
"version": "0.2.0",
```
- [ ] **Step 4: Verify JSON parses and new entries are correct**
```bash
cd /home/claude/projects/openclaw-egp-plugin && \
jq -e '
.version == "0.2.0"
and (.skills | length == 6)
and (.skills | contains(["skills/procurement-analysis"]))
' openclaw.plugin.json && echo "OK manifest"
```
Expected: prints `true` then `OK manifest`. Non-zero exit = STOP and fix.
- [ ] **Step 5: Commit**
```bash
cd /home/claude/projects/openclaw-egp-plugin && \
git add openclaw.plugin.json && \
git commit -m "$(cat <<'EOF'
chore(manifest): register procurement-analysis skill, bump to v0.2.0
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
EOF
)"
```
Expected: commit succeeds.
---
## Task 3: Tag `v0.2.0`
- [ ] **Step 1: Verify both prior commits are present**
```bash
cd /home/claude/projects/openclaw-egp-plugin && git log --oneline -5
```
Expected: top 2 lines are the manifest update commit (most recent) then the SKILL.md commit. Below that, the spec doc commits from earlier work.
- [ ] **Step 2: Create the tag**
```bash
cd /home/claude/projects/openclaw-egp-plugin && git tag v0.2.0
```
Expected: no output, exit 0.
- [ ] **Step 3: Verify tag exists and points at HEAD**
```bash
cd /home/claude/projects/openclaw-egp-plugin && \
git tag -l v0.2.0 && \
[ "$(git rev-list -n 1 v0.2.0)" = "$(git rev-parse HEAD)" ] && echo "OK tag on HEAD"
```
Expected: prints `v0.2.0` then `OK tag on HEAD`.
---
## Task 4: Manual smoke test (post-install)
This task is **manual** — it requires the openclaw-egp-server running and the plugin loaded into Claude Code (or OpenClaw). It cannot be automated within the plan. Skip if the implementer doesn't have a running server.
- [ ] **Step 1: Confirm server is up**
```bash
curl -s -o /dev/null -w "%{http_code}\n" http://127.0.0.1:8000/healthz
```
Expected: `200`. If not 200, start the server per `openclaw-egp-server` README before continuing.
- [ ] **Step 2: Confirm `.mcp.json` in the consumer project points to `/mcp`**
```bash
cat /home/claude/projects/openclaw-procurement-data-layer/.mcp.json
```
Expected: contains `"url": "http://127.0.0.1:8000/mcp"` (or matching `PUBLIC_BASE_URL`).
- [ ] **Step 3: Reload Claude Code MCP servers**
In the Claude Code session, run `/mcp` to reconnect; verify `openclaw-egp` is listed and the 5 tools are reachable.
- [ ] **Step 4: Run the 6 smoke queries and record observed behavior**
For each query, expected intent is in parentheses. Record actual behavior in a scratchpad (or comment on PR).
1. "Tìm hồ sơ mời thầu y tế" — (DISCOVERY) — expect: candidate table, no full 5-part analysis.
2. "Phân tích E-HSMT IB2600186834-01" — (DEEP_ANALYSIS) — expect: full 5-part schema for that entity, Part 3 + Part 4 both expanded.
3. "Gói IB2600186834-01 nhà thầu cần chuẩn bị gì?" — (DEEP_ANALYSIS, bidder lens) — expect: Part 3 expanded, Part 4 marked `(không phải trọng tâm câu hỏi, rút gọn)`.
4. "Hồ sơ IB2600186834-01 có rủi ro gì không?" — (RISK_AUDIT) — expect: 5-part, Part 5 expanded.
5. "TBMT IB2600186834-01 và KHLCNT có khớp nhau không?" — (CROSS_DOC_AUDIT) — expect: hybrid candidate resolution; if multiple matches, agent asks user to pick; then field-by-field compare table in Part 4.
6. "Bên mời thầu IB2600186834-01 đã đăng đủ thông tin chưa?" — (RISK_AUDIT, publisher lens) — expect: Part 4 expanded, Part 3 marked rút gọn.
For each: confirm citations follow the `[entity_code | source_file | page=N | … | link_status=…]` format, and that any missing field uses the exact phrase "không thấy trong nguồn đã truy xuất" (NOT blank, NOT "không có").
- [ ] **Step 5: If a query fails or behavior diverges from expected, file an issue (do NOT silently fix)**
Filing an issue rather than fixing inline preserves the boundary: this plan implemented the skill content; behavior drift means either the skill content needs revision (new task) or the server retrieval is weak (separate concern).
---
## Final verification
After Task 3 completes:
- [ ] **Confirm overall state**
```bash
cd /home/claude/projects/openclaw-egp-plugin && \
git status && \
git log --oneline -3 && \
git tag -l v0.2.0 && \
ls skills/procurement-analysis/ && \
jq '.version, .skills | length' openclaw.plugin.json
```
Expected:
- working tree clean
- top 2 commits: manifest update + SKILL.md add
- `v0.2.0` tag listed
- `skills/procurement-analysis/` contains `SKILL.md`
- version `"0.2.0"` and skills array length `6`
---
## Push (optional, only on explicit user request)
Do NOT push automatically. If the user requests it:
```bash
cd /home/claude/projects/openclaw-egp-plugin && git push origin main --follow-tags
```

@ -0,0 +1,269 @@
# Procurement Analysis Skill — Design Spec
**Date:** 2026-05-16
**Status:** Draft (awaiting user approval)
**Repo:** `openclaw-egp-plugin`
**Skill path:** `skills/procurement-analysis/SKILL.md`
---
## 1. Goal
Add a workflow-level orchestrator skill to `openclaw-egp-plugin` that guides an OpenClaw agent to act as a domain expert + agentic RAG analyst over Vietnamese e-procurement documents (TBMT / KHLCNT / LCNT / E-HSMT) on the National Public Procurement Network.
The skill turns the existing 5 tool-level skills (`search-procurement-docs`, `list-entities`, `describe-entity`, `fetch-raw-file`, `entity-types-glossary`) into a coherent analytical workflow with intent routing, evidence orchestration, and a fixed output schema.
## 2. Non-goals
- No per-industry skills (no `medical-tender`, `it-tender`, `construction-tender`). Industries are query keywords/filters only.
- No new MCP tools. Skill orchestrates the 5 existing tools.
- No new server endpoints, no DB schema change, no data model migration.
- No knowledge-base content about procurement law/regulations in the skill — skill analyzes only what's in the retrieved documents.
## 3. Approach (selected: A — Single orchestrator skill)
- Keep the 5 thin tool-level skills unchanged. They give per-tool usage guidance.
- Add **one new skill** `procurement-analysis` at workflow level.
- Two-tier architecture: workflow skill (this) above, tool skills (existing) below. No overlap in `description:` fronmatter — the new skill describes business analysis, tool skills describe single-tool usage.
- Plugin manifest gets one new entry in `skills` array; everything else unchanged.
## 4. Skill file structure
```
skills/procurement-analysis/
└── SKILL.md
```
Single file. No supporting Python/JS — skill is pure prompt content for the agent.
## 5. SKILL.md — front matter
```yaml
---
name: procurement-analysis
description: Phân tích chuyên sâu hồ sơ đấu thầu Việt Nam (TBMT/KHLCNT/LCNT/E-HSMT) theo 2 góc nhìn nhà thầu + chủ đầu tư. Dùng khi user hỏi tìm/phân tích/audit/so sánh gói thầu — KHÔNG dùng cho tra cứu định nghĩa thuật ngữ hay tải file đơn lẻ.
---
```
## 6. Intent routing
Skill instructs the agent to classify the user query into one of four intents BEFORE any tool call:
| Intent | Trigger signals | Output mode |
|--------|----------------|-------------|
| **DISCOVERY** | "tìm", "có gói nào", "các gói … đang mở", industry keyword (y tế, CNTT, xây lắp...) without entity_code | Candidate table (Section 7) — no full analysis |
| **DEEP_ANALYSIS** | User names 1 entity_code, or asks "phân tích gói X", "nhà thầu cần chuẩn bị gì cho X" | Full 5-part schema (Section 8) |
| **CROSS_DOC_AUDIT** | "TBMT/KHLCNT/E-HSMT có khớp không", "có sửa đổi không", "có gia hạn không" | Full 5-part schema + cross-doc compare table |
| **RISK_AUDIT** | "rủi ro", "đã đăng đủ chưa", "có gì bất thường" | Full 5-part schema, emphasis on Section 5 |
If the agent cannot classify confidently (signals overlap or are missing), it MUST ask the user to clarify before running any tool. It MUST NOT default to deep analysis.
## 7. DISCOVERY mode output
When intent = DISCOVERY:
**Workflow:**
1. Extract keyword/filter from user question: industry, goods/services, location, status, time window, value range if any.
2. Retrieve candidate list using `list_entities(entity_type?)` + `search_procurement_docs(query=<extracted keyword>)`. Cap at top 1020 results.
3. Render the candidate table below — **do not** run full 5-part analysis for each item.
4. End with: "Đây là danh sách candidate, chưa phải phân tích đầy đủ. Vui lòng chọn `entity_code` để chạy phân tích sâu." Suggest refinement filters if results > 20.
5. If any candidate has urgent deadline or visible risk indicator, list it under "Ưu tiên xem trước" before the table.
**Candidate table columns:**
- `rank`
- `entity_type`
- `entity_code`
- `tên gói / thông báo / kế hoạch`
- `bên mời thầu / chủ đầu tư` (if available)
- `giá gói thầu` (if available)
- `deadline / đóng thầu` (if available)
- `trạng thái` (if available)
- `highlight ngắn`: match reason or noteworthy point
- `citation / source`
**Triggers that bypass DISCOVERY and go straight to DEEP_ANALYSIS:**
- User explicitly says "phân tích luôn top 3 / top 5".
- Search returns exactly 1 candidate AND the retrieval tool flags it as a strong match (score top-1 noticeably above next candidate; agent uses judgment). If in doubt, stay in DISCOVERY and ask the user to confirm.
## 8. DEEP_ANALYSIS output schema (5 parts)
This schema is rendered when intent = DEEP_ANALYSIS, CROSS_DOC_AUDIT, or RISK_AUDIT.
### Part 1 — Tóm tắt gói thầu
- Mã TBMT/E-TBMT
- Mã KHLCNT
- Tên gói thầu
- Chủ đầu tư / Bên mời thầu
- Trạng thái: đang mở / đã đóng / đã hủy / đã gia hạn — **only conclude when `bidCloseDate` / `status` / explicit source field is present**; otherwise: "không xác định từ nguồn đã truy xuất".
- One-sentence intent-aware conclusion.
### Part 2 — Thông tin KHLCNT / TBMT / E-HSMT quan trọng
Compact comparison table:
| Trường | KHLCNT | TBMT | E-HSMT |
|--------|--------|------|--------|
| Giá gói thầu | … | … | — |
| Nguồn vốn | … | … | — |
| Hình thức LCNT | … | … | … |
| Phương thức LCNT | … | … | … |
| Loại hợp đồng | … | … | … |
| Thời gian thực hiện | … | … | … |
| Bảo đảm dự thầu | — | … | … |
| Thời điểm phát hành / đóng / mở thầu | — | … | … |
| Chia lô | … | … | … |
| Địa điểm | … | … | … |
Cell semantics:
- `…` — placeholder for actual value extracted from the document.
- `—` (em dash) — field intentionally not applicable for that document type (e.g., "Bảo đảm dự thầu" doesn't apply to KHLCNT).
- `không thấy trong nguồn đã truy xuất` — field applies in principle but was not found in retrieved chunks.
Never blank, never guessed. Never render `…` literally in agent output.
### Part 3 — Phân tích theo góc nhìn nhà thầu
When intent is bidder-focused → render full bullet list below. When intent is publisher-focused or audit → render header with suffix `(không phải trọng tâm câu hỏi, rút gọn)` and keep only 23 conclusion bullets.
Bullets:
- **Điều kiện tham dự**: tư cách hợp lệ, liên danh, nhà thầu phụ, bảo đảm dự thầu (giá trị + hình thức).
- **Năng lực & kinh nghiệm yêu cầu**: hợp đồng tương tự, doanh thu, nhân sự chủ chốt, thiết bị.
- **Tiêu chuẩn đánh giá**: hợp lệ / kỹ thuật / tài chính / giá — đạt-không-đạt hoặc chấm điểm; trọng số nếu có.
- **Phạm vi & danh mục**: HHDV / công việc / chia lô / địa điểm giao.
- **Hồ sơ cần chuẩn bị (checklist)**: E-HSDT, đơn dự thầu, bảo lãnh, biểu giá, đề xuất KT, đề xuất TC, tài liệu chứng minh.
- **Rủi ro tham dự**: deadline gấp / tiêu chí khó / chứng minh nặng / thiếu thông tin → đề xuất gửi yêu cầu làm rõ.
- **Kết luận tham dự**: ① Nên xem xét tham dự / ② Cần kiểm tra thêm / ③ Rủi ro cao — kèm lý do.
### Part 4 — Phân tích theo góc nhìn chủ đầu tư / bên mời thầu
When intent is publisher-focused or audit → full bullet list. Otherwise → suffix and 23 conclusion bullets.
Bullets:
- **Audit KHLCNT**: đủ phê duyệt / giá / nguồn vốn / hình thức&phương thức / loại HĐ / thời gian thực hiện?
- **Audit TBMT**: đủ mã / tên gói / bên mời / chủ đầu tư / mốc thời gian / bảo đảm / trạng thái?
- **Audit E-HSMT**: đủ Chỉ dẫn NT / Bảng dữ liệu / Tiêu chuẩn ĐG / YC kỹ thuật / Biểu mẫu / Điều kiện HĐ / Mẫu HĐ?
- **Khớp giữa 3 hồ sơ** (chỉ render khi CROSS_DOC_AUDIT or related docs available): bảng so sánh field-by-field, ✓ / ✗ / "không kiểm tra được".
- **Sửa đổi / gia hạn / làm rõ**: có hay không, phiên bản mới nhất.
- **Kết luận audit**: ① Đủ để công khai / ② Cần bổ sung / ③ Rủi ro cần rà soát pháp lý — kèm lý do.
### Part 5 — Rủi ro, điểm cần làm rõ & nguồn trích dẫn
- **Rủi ro & cảnh báo** — bulleted; each bullet has inline citation.
- **Câu hỏi / dữ liệu cần bổ sung** — bullet list of what's missing for completeness.
- **Nguồn trích dẫn** — final table for every important claim in Parts 3 & 4:
| entity_code | source_file | page | mục/section | chunk_id | link_status |
|-------------|-------------|------|-------------|----------|-------------|
## 9. Citation rules
**Format:** `[entity_code | source_file | page=N | mục/section nếu có | chunk_id nếu có | link_status=confirmed|inferred]`
**Required fields per claim:** `entity_code`, `source_file`, `page`.
**Missing-page rule:** when the retrieval tool does not return a page for a chunk, write `page=không có trong metadata`. Never omit the page field.
**Section/mục rule:** only fill `mục/section` when the chunk text itself contains a heading (e.g., "Chương III, mục 2.1"). Never infer a heading from surrounding context.
**chunk_id rule:** include if the tool returns it. Currently `search_procurement_docs` does not return `chunk_id` directly; treat as optional. (Future server work may add it.)
**Multi-source claim rule:** when a claim aggregates information from multiple chunks/files, cite all source rows or end the citation with "tổng hợp từ nhiều nguồn".
**link_status rule:**
- `confirmed` — user provided the related code, OR one document's text explicitly names the other document's code.
- `inferred` — link discovered via fuzzy code match, prefix/substring, similarity, or content-based search. Any cross-doc claim resting on `inferred` link MUST be prepended with "Suy luận, cần xác nhận".
## 10. Anti-hallucination rules (skill MUST instruct agent to follow)
1. **Strict type discrimination**: KHLCNT (kế hoạch) ≠ TBMT (thông báo) ≠ LCNT (quy trình) ≠ E-HSMT (hồ sơ điện tử). Never conflate.
2. **No inference filler**: when a field is absent, write "không thấy trong nguồn đã truy xuất". Never substitute with "thường thì..." or general industry knowledge.
3. **"Không thấy" ≠ "không có"**: missing-from-retrieval does not imply the field is absent from reality. Never restate the former as the latter.
4. **Multi-evidence requirement**: do not draw conclusions from only the top-1 result. Inspect at least 35 results; if fewer than 3 hits, expand the query or rephrase before concluding insufficient evidence.
5. **Hit-count transparency**: when total hits < 3, report the actual hit count and explicitly note evidence is incomplete.
6. **Status conclusion gate**: do not conclude "đang mở / đã đóng / đã hủy" unless `bidCloseDate`, `status`, or a source field explicitly states it.
7. **Conclusion strength gate**: when citation is weak (≤ 1 cite, or cite content doesn't match the claim), drop strong conclusions ("nên tham dự" / "đủ để công khai" / "rủi ro pháp lý") and fall back to "cần kiểm tra thêm" or "không đủ dữ liệu để kết luận".
8. **Retrieval-weakness reporting**: if results = [] or `limitations` warning present, state the limit and propose extra files / keywords / refinements.
9. **Ambiguous industry keyword expansion**: when the industry keyword is vague (e.g., "y tế" → may cover thiết bị, dược, vật tư, dịch vụ y tế), the agent MAY expand the query with business-relevant synonyms — but MUST log the exact keywords used in the response.
## 11. Tool orchestration mapping
| Intent | Tools to call (in order) | Purpose |
|--------|--------------------------|---------|
| DISCOVERY | `list_entities(entity_type?)``search_procurement_docs(query=<keywords>, limit=1020)` | Build candidate table |
| DEEP_ANALYSIS | `describe_entity(entity_code)` → multiple `search_procurement_docs(query=<field-specific>, entity_code=...)` for: giá, nguồn vốn, deadline, tiêu chuẩn đánh giá, năng lực, tiêu chí kỹ thuật, bảo đảm dự thầu, biểu mẫu | Fill 5-part schema |
| CROSS_DOC_AUDIT | `list_entities` (fuzzy code candidates) → `search_procurement_docs(query=<code A>)` to find mentions of A inside B's text → if > 1 candidate, ASK USER → field-by-field compare via `search_procurement_docs` per field | Compare KHLCNT vs TBMT vs E-HSMT |
| RISK_AUDIT | Same as DEEP_ANALYSIS + completeness checklist for E-HSMT mandatory sections | Highlight Part 5 |
Skill must not over-explain HOW each tool works — that's the job of the 5 thin tool-level skills. This skill says only WHICH tool to use WHEN.
## 12. Industry keyword handling
User says "y tế" / "CNTT" / "xây lắp" / "tư vấn" / "dược":
1. Extract keyword(s).
2. Use as `query` for `search_procurement_docs` and post-hoc filter on `list_entities`.
3. Output remains the common schema. Industry is filter input only.
4. If keyword is vague, expand with documented synonyms (see Rule 11.9) and log the expansion.
No industry-specific section, sub-skill, or template is created.
## 13. Anti-patterns (skill MUST list explicitly)
- ❌ Trả lời từ trí nhớ / kiến thức nền thay vì gọi tool.
- ❌ Chỉ gọi 1 tool rồi kết luận — phải orchestrate (list + search + describe).
- ❌ Lấy top-1 result làm sự thật duy nhất.
- ❌ Gộp KHLCNT/TBMT/LCNT/E-HSMT thành một khái niệm "hồ sơ".
- ❌ Kết luận trạng thái khi không có mốc thời gian / `status` field.
- ❌ Cite chung chung "theo hồ sơ" — phải đủ `entity_code + source_file + page`.
- ❌ Bỏ trống `page` thay vì ghi `page=không có trong metadata`.
- ❌ Suy diễn cross-doc link mà không gắn `link_status=inferred` + cảnh báo "Suy luận, cần xác nhận".
- ❌ Skip "cần kiểm tra thêm" để ra kết luận mạnh khi cite yếu.
- ❌ Chuyển "không thấy trong nguồn đã truy xuất" thành "không có" trong gói thầu.
- ❌ Tạo Section ngành riêng (vd. "phân tích y tế") — schema phải common.
- ❌ Render full 5-part cho discovery query (chỉ candidate table + summary ngắn trừ khi user yêu cầu rõ).
- ❌ Mở rộng keyword ngành bằng synonym mà không log keyword đã dùng.
## 14. Manifest update
Edit `openclaw.plugin.json`:
```json
{
"skills": [
"skills/search-procurement-docs",
"skills/list-entities",
"skills/describe-entity",
"skills/fetch-raw-file",
"skills/entity-types-glossary",
"skills/procurement-analysis"
]
}
```
Bump `version` from `0.1.0` to `0.2.0`.
## 15. Verification
The skill is content-only (no code). Verification steps:
1. **Manifest validation**: `openclaw.plugin.json` parses, `skills` array references existing folder, version bumped.
2. **Frontmatter validation**: SKILL.md has valid YAML frontmatter with `name` + `description`.
3. **Content review**: spec sections 613 are present in SKILL.md (intent routing, both output modes, citation rules, anti-hallucination rules, tool mapping, industry handling, anti-patterns).
4. **Manual smoke test** (post-install): invoke each of the 6 example user queries from the original brainstorm prompt and verify the agent picks `procurement-analysis` (not the wrong tool skill) and follows the expected workflow:
- "Tìm hồ sơ mời thầu y tế" → DISCOVERY → candidate table.
- "Phân tích E-HSMT IB2600186834-01" → DEEP_ANALYSIS → 5-part schema.
- "Gói IB2600186834-01 nhà thầu cần chuẩn bị gì?" → DEEP_ANALYSIS, Part 3 expanded.
- "Hồ sơ IB2600186834-01 có rủi ro gì không?" → RISK_AUDIT, Part 5 expanded.
- "TBMT IB2600186834-01 và KHLCNT có khớp nhau không?" → CROSS_DOC_AUDIT → hybrid candidate resolution → compare table.
- "Bên mời thầu IB2600186834-01 đã đăng đủ thông tin chưa?" → RISK_AUDIT, Part 4 expanded.
## 16. Tagging / release
After commit + skill content review, tag plugin repo `v0.2.0` to align with the manifest version bump.
## 17. Out of scope (explicitly deferred)
- Adding a `package_id` foreign key in the server DB to link KHLCNT ↔ TBMT ↔ E-HSMT natively. The hybrid heuristic in Section 11 covers the cross-doc audit use case meanwhile.
- Returning `chunk_id` + `section_heading` from `search_procurement_docs`. Today's payload is sufficient for the citation format; richer fields can be added later without breaking the skill.
- Multi-language support. Skill output is Vietnamese only.
- Programmatic schema validation of agent output. The 5-part schema is for the agent to follow, not for automated checking in this iteration.

@ -2,7 +2,7 @@
"id": "openclaw-egp", "id": "openclaw-egp",
"name": "OpenClaw EGP", "name": "OpenClaw EGP",
"description": "RAG over Vietnamese government procurement documents (TBMT, KHLCNT, KQLCNT). Connects an OpenClaw agent to a running openclaw-egp-server instance via remote MCP.", "description": "RAG over Vietnamese government procurement documents (TBMT, KHLCNT, KQLCNT). Connects an OpenClaw agent to a running openclaw-egp-server instance via remote MCP.",
"version": "0.1.0", "version": "0.2.0",
"configSchema": { "configSchema": {
"type": "object", "type": "object",
"required": ["serverUrl"], "required": ["serverUrl"],
@ -25,7 +25,8 @@
"skills/list-entities", "skills/list-entities",
"skills/describe-entity", "skills/describe-entity",
"skills/fetch-raw-file", "skills/fetch-raw-file",
"skills/entity-types-glossary" "skills/entity-types-glossary",
"skills/procurement-analysis"
], ],
"contracts": { "contracts": {
"tools": [ "tools": [

@ -0,0 +1,219 @@
---
name: procurement-analysis
description: Phân tích chuyên sâu hồ sơ đấu thầu Việt Nam (TBMT/KHLCNT/LCNT/E-HSMT) theo 2 góc nhìn nhà thầu + chủ đầu tư. Dùng khi user hỏi tìm/phân tích/audit/so sánh gói thầu — KHÔNG dùng cho tra cứu định nghĩa thuật ngữ hay tải file đơn lẻ.
---
# Procurement Analysis
Bạn đóng vai chuyên gia nghiệp vụ đấu thầu qua mạng Việt Nam và agentic RAG analyst trên kho hồ sơ E-GP. Mục tiêu: phân tích KHLCNT, TBMT, LCNT, E-HSMT chính xác, có trích dẫn, và **không suy diễn**.
## Khi nào dùng
Dùng skill này khi user hỏi:
- "Tìm hồ sơ mời thầu …", "có gói nào về …", từ khóa ngành (y tế, CNTT, xây lắp, dược…).
- "Phân tích E-HSMT/TBMT/KHLCNT mã X", "gói X có gì".
- "Nhà thầu cần chuẩn bị gì cho gói X", "có nên tham dự gói X".
- "Hồ sơ X có rủi ro gì", "có gì bất thường", "đã đăng đủ chưa".
- "TBMT, KHLCNT, E-HSMT có khớp nhau không", "có sửa đổi/gia hạn không".
KHÔNG dùng skill này khi:
- User hỏi định nghĩa thuật ngữ → `entity-types-glossary`.
- User chỉ muốn tải file gốc → `fetch-raw-file`.
- User hỏi câu single-tool không cần workflow → 5 thin skill trực tiếp.
## Bước 0 — Phân loại intent (LUÔN làm đầu tiên)
Phân loại câu hỏi vào 1 trong 4 intent:
| Intent | Trigger | Output mode |
|--------|---------|-------------|
| `DISCOVERY` | "tìm", "có gói nào", "các gói đang mở", keyword ngành, KHÔNG có entity_code | Candidate table (Bước 1) |
| `DEEP_ANALYSIS` | User nêu rõ 1 entity_code; "phân tích gói X"; "nhà thầu cần chuẩn bị gì cho X" | Full 5-part schema |
| `CROSS_DOC_AUDIT` | "TBMT/KHLCNT/E-HSMT có khớp không"; "có sửa đổi/gia hạn không" | Full 5-part + bảng compare |
| `RISK_AUDIT` | "rủi ro", "đã đăng đủ chưa", "có gì bất thường" | Full 5-part, nhấn Part 5 |
**Priority khi nhiều trigger cùng fire** (ví dụ query có cả `entity_code` và keyword "rủi ro"):
1. `CROSS_DOC_AUDIT` keyword ("có khớp không", "có sửa đổi/gia hạn không") thắng → route sang CROSS_DOC_AUDIT.
2. Còn lại, `RISK_AUDIT` keyword ("rủi ro", "đã đăng đủ chưa", "có gì bất thường") thắng → route sang RISK_AUDIT.
3. Còn lại, nếu có `entity_code` → DEEP_ANALYSIS.
4. Không có `entity_code` và không có keyword đặc trưng → DISCOVERY.
**Nếu vẫn không rõ** sau priority (query không khớp pattern nào; hoặc CROSS_DOC_AUDIT/RISK_AUDIT không có `entity_code` làm anchor): HỎI user clarify trước khi gọi tool. KHÔNG default sang deep analysis.
## Bước 1 — DISCOVERY workflow
Khi `intent = DISCOVERY`:
1. Extract keyword/filter từ câu hỏi: ngành, hàng hóa/dịch vụ, địa điểm, trạng thái, thời gian, khoảng giá.
2. Gọi `list_entities(entity_type?)` (filter loại nếu user chỉ định) + `search_procurement_docs(query=<keyword>, limit=10..20)`.
3. Trả **bảng candidate** với cột:
- `rank` | `entity_type` | `entity_code` | `tên gói/thông báo/kế hoạch` | `bên mời thầu/chủ đầu tư` (nếu có) | `giá gói thầu` (nếu có) | `deadline/đóng thầu` (nếu có) | `trạng thái` (nếu có) | `highlight ngắn` (lý do match hoặc điểm đáng chú ý) | `citation/source`.
4. **KHÔNG run full 5-part analysis** cho từng candidate.
5. Trước bảng, nếu có candidate deadline gấp / rủi ro nổi: thêm mục "**Ưu tiên xem trước**".
6. Sau bảng:
- Nêu rõ "Đây là danh sách candidate, chưa phải phân tích đầy đủ."
- Gợi ý user pick 1 `entity_code` để chạy phân tích sâu.
- Nếu kết quả > 20: gợi ý refine filter (địa điểm, khoảng giá, trạng thái, thời gian, loại gói).
**Auto-promote sang DEEP_ANALYSIS chỉ khi:**
- User yêu cầu rõ "phân tích luôn top 3/top 5".
- HOẶC search trả đúng 1 candidate điểm cao rõ rệt hơn phần còn lại. Còn lưỡng lự → ở lại DISCOVERY và hỏi user.
## Bước 2 — DEEP_ANALYSIS / RISK_AUDIT / CROSS_DOC_AUDIT workflow
Khi intent thuộc 3 nhóm này, render đủ **schema 5 phần** ở dưới.
### Tool orchestration
| Intent | Tools gọi (theo thứ tự) | Mục đích |
|--------|--------------------------|----------|
| DEEP_ANALYSIS | `describe_entity(entity_code)` → nhiều lượt `search_procurement_docs(query=<field-specific>, entity_code=...)` cho từng trường: giá, nguồn vốn, deadline, tiêu chuẩn ĐG, năng lực, bảo đảm dự thầu, biểu mẫu | Fill 5 phần |
| CROSS_DOC_AUDIT | `list_entities` (fuzzy code candidates) → `search_procurement_docs(query=<mã A>)` để tìm mã A được nhắc trong text của B → **nếu > 1 candidate, HỎI user pick** → field-by-field compare qua `search_procurement_docs` cho từng trường | So sánh KHLCNT vs TBMT vs E-HSMT |
| RISK_AUDIT | Giống DEEP_ANALYSIS + checklist completeness các phần bắt buộc E-HSMT | Trọng tâm Part 5 |
**KHÔNG over-explain HOW tool work** — đó là việc của 5 thin skill. Skill này chỉ nói WHICH tool, WHEN.
### Schema 5 phần — render đầy đủ
#### Part 1 — Tóm tắt gói thầu
- Mã TBMT/E-TBMT
- Mã KHLCNT
- Tên gói thầu
- Chủ đầu tư / Bên mời thầu
- **Trạng thái**: đang mở / đã đóng / đã hủy / đã gia hạn. **Chỉ kết luận khi**`bidCloseDate`, `status`, hoặc trường nguồn ghi rõ. Thiếu dữ liệu → "không xác định từ nguồn đã truy xuất".
- 1 câu kết luận theo intent.
#### Part 2 — Thông tin KHLCNT / TBMT / E-HSMT quan trọng
Bảng so sánh:
| Trường | KHLCNT | TBMT | E-HSMT |
|--------|--------|------|--------|
| Giá gói thầu | … | … | — |
| Nguồn vốn | … | … | — |
| Hình thức LCNT | … | … | … |
| Phương thức LCNT | … | … | … |
| Loại hợp đồng | … | … | … |
| Thời gian thực hiện | … | … | … |
| Bảo đảm dự thầu | — | … | … |
| Thời điểm phát hành / đóng / mở thầu | — | … | … |
| Chia lô | … | … | … |
| Địa điểm | … | … | … |
Quy ước cell:
- Giá trị thực: điền vào (KHÔNG render `…` literal).
- `—` (em dash) = trường KHÔNG ÁP DỤNG cho loại hồ sơ đó.
- `không thấy trong nguồn đã truy xuất` = trường áp dụng nhưng chunk không có dữ liệu.
**KHÔNG bỏ trống. KHÔNG đoán.**
#### Part 3 — Góc nhìn nhà thầu
**Khi render FULL Part 3 (bidder lens):**
- Intent = `DEEP_ANALYSIS` và câu hỏi nhắm nhà thầu ("nhà thầu cần chuẩn bị gì", "có nên dự", "yêu cầu năng lực").
- Intent = `DEEP_ANALYSIS` không thiên về góc nào (render full cả Part 3 + Part 4).
- Intent = `RISK_AUDIT` (Part 3 + Part 4 đều full để cover rủi ro 2 chiều, Part 5 nhấn).
**Khi RÚT GỌN Part 3:**
- Intent = `DEEP_ANALYSIS` và câu hỏi nhắm chủ đầu tư/audit ("đã đăng đủ chưa", "kiểm tra hồ sơ công khai").
- Intent = `CROSS_DOC_AUDIT` (trọng tâm là so sánh, không phải prep dự thầu).
Khi rút gọn: header thêm hậu tố `(không phải trọng tâm câu hỏi, rút gọn)` và chỉ render đúng 2 bullet: **Kết luận tham dự** + **Rủi ro tham dự**. Bỏ các bullet khác.
- **Điều kiện tham dự**: tư cách hợp lệ, liên danh, nhà thầu phụ, bảo đảm dự thầu (giá trị + hình thức).
- **Năng lực & kinh nghiệm**: hợp đồng tương tự, doanh thu, nhân sự chủ chốt, thiết bị.
- **Tiêu chuẩn đánh giá**: hợp lệ / kỹ thuật / tài chính / giá — đạt-không-đạt hoặc chấm điểm; trọng số.
- **Phạm vi & danh mục**: HHDV / công việc / chia lô / địa điểm giao.
- **Hồ sơ cần chuẩn bị (checklist)**: E-HSDT, đơn dự thầu, bảo lãnh, biểu giá, đề xuất KT, đề xuất TC, tài liệu chứng minh.
- **Rủi ro tham dự**: deadline gấp / tiêu chí khó / chứng minh nặng / thông tin thiếu → đề xuất gửi yêu cầu làm rõ.
- **Kết luận tham dự**: ① Nên xem xét tham dự / ② Cần kiểm tra thêm / ③ Rủi ro cao — kèm lý do.
#### Part 4 — Góc nhìn chủ đầu tư / bên mời thầu
**Khi render FULL Part 4 (publisher/audit lens):**
- Intent = `DEEP_ANALYSIS` và câu hỏi nhắm chủ đầu tư/audit ("đã đăng đủ chưa", "kiểm tra hồ sơ công khai").
- Intent = `CROSS_DOC_AUDIT` (luôn full vì cần bảng compare).
- Intent = `RISK_AUDIT` (cả Part 3 + Part 4 đều full, Part 5 nhấn).
- Intent = `DEEP_ANALYSIS` không thiên về góc nào (render full cả Part 3 + Part 4).
**Khi RÚT GỌN Part 4:**
- Intent = `DEEP_ANALYSIS` và câu hỏi nhắm nhà thầu ("nhà thầu cần chuẩn bị gì", "có nên dự").
Khi rút gọn: header thêm hậu tố `(không phải trọng tâm câu hỏi, rút gọn)` và chỉ render đúng 2 bullet: **Kết luận audit** + 1 bullet highlight quan trọng nhất (vd. trường thiếu nghiêm trọng hoặc lệch giữa 3 hồ sơ). Bỏ các bullet khác.
- **Audit KHLCNT**: đủ phê duyệt / giá / nguồn vốn / hình thức&phương thức / loại HĐ / thời gian thực hiện?
- **Audit TBMT**: đủ mã / tên gói / bên mời / chủ đầu tư / mốc thời gian / bảo đảm / trạng thái?
- **Audit E-HSMT**: đủ Chỉ dẫn NT / Bảng dữ liệu / Tiêu chuẩn ĐG / YC kỹ thuật / Biểu mẫu / Điều kiện HĐ / Mẫu HĐ?
- **Khớp giữa 3 hồ sơ** (chỉ render khi CROSS_DOC_AUDIT hoặc đã tìm được related docs): bảng compare field-by-field, ✓ / ✗ / "không kiểm tra được".
- **Sửa đổi / gia hạn / làm rõ**: có/không, phiên bản mới nhất.
- **Kết luận audit**: ① Đủ để công khai / ② Cần bổ sung / ③ Rủi ro cần rà soát pháp lý — kèm lý do.
#### Part 5 — Rủi ro, điểm cần làm rõ & nguồn trích dẫn
- **Rủi ro & cảnh báo** — bullet, mỗi cái có cite inline.
- **Câu hỏi / dữ liệu cần bổ sung** — bullet list những gì hồ sơ thiếu.
- **Bảng nguồn trích dẫn** — cho mọi claim quan trọng ở Part 3 & 4:
| entity_code | source_file | page | mục/section | chunk_id | link_status |
|-------------|-------------|------|-------------|----------|-------------|
## Bước 3 — Citation rules
Định dạng claim cite: `[entity_code | source_file | page=N | mục/section nếu có | chunk_id nếu có | link_status=confirmed|inferred]`
- **Required mỗi claim**: `entity_code`, `source_file`, `page`.
- **Page thiếu**: ghi `page=không có trong metadata`. KHÔNG bỏ trống field page.
- **Mục/section**: chỉ điền khi chunk text chứa heading rõ ràng (vd. "Chương III, mục 2.1"). KHÔNG suy heading từ context xung quanh.
- **chunk_id**: nếu tool trả về thì điền (hiện `search_procurement_docs` chưa trả `chunk_id` → optional).
- **Claim tổng hợp nhiều chunk/file**: cite tất cả nguồn, hoặc thêm note "tổng hợp từ nhiều nguồn".
- **link_status**:
- `confirmed`: user trực tiếp nêu mã liên quan, HOẶC 1 hồ sơ trực tiếp nêu mã hồ sơ kia trong text.
- `inferred`: tìm bằng fuzzy code / similarity / content-search. Mọi claim cross-doc dùng `inferred` **bắt buộc** mở đầu: "Suy luận, cần xác nhận".
## Bước 4 — Anti-hallucination rules (BẮT BUỘC)
1. **Phân biệt nghiêm 4 loại**: KHLCNT (kế hoạch) ≠ TBMT (thông báo) ≠ LCNT (quy trình) ≠ E-HSMT (hồ sơ điện tử). Không gộp.
2. **Không filler suy diễn**: trường thiếu → "không thấy trong nguồn đã truy xuất". KHÔNG dùng "thường thì..." hoặc kiến thức chung.
3. **"Không thấy" ≠ "không có"**: thiếu trong retrieve KHÔNG có nghĩa thực tế gói thầu không có. Không chuyển nhãn.
4. **Đa bằng chứng**: check ≥ 3-5 results, không kết luận từ top-1. Nếu < 3 hits, expand query / rephrase trước khi nói "thiếu chng cứ".
5. **Báo hit count khi < 3**: ghi rõ số hit thực tế, đánh dấu bằng chứng chưa đủ.
6. **Status conclusion gate**: KHÔNG kết luận "đang mở/đã đóng/đã hủy" nếu thiếu mốc thời gian / `status`.
7. **Conclusion strength gate**: cite yếu (≤ 1 cite, hoặc cite không match claim) → bỏ kết luận mạnh ("nên tham dự" / "đủ công khai" / "rủi ro pháp lý"), fallback sang "cần kiểm tra thêm" hoặc "không đủ dữ liệu để kết luận".
8. **Retrieval-weakness reporting**: results = [] hoặc `limitations` có warning → báo rõ giới hạn + đề xuất thêm file/keyword.
9. **Industry synonym expansion**: keyword mơ hồ (vd. "y tế" → thiết bị / dược / vật tư / dịch vụ) → có thể expand, NHƯNG bắt buộc log keyword đã dùng trong reply.
## Bước 5 — Industry keyword handling
User hỏi "y tế" / "CNTT" / "xây lắp" / "tư vấn" / "dược"...:
1. Extract keyword(s).
2. Dùng làm `query` cho `search_procurement_docs` + post-hoc filter trên `list_entities`.
3. Output **vẫn theo schema common**. Industry chỉ là filter input.
4. KHÔNG tạo section "phân tích ngành" — schema phải common cho mọi gói.
5. Nếu expand synonym (Rule 9): log keyword đã dùng.
## Anti-patterns
- ❌ Trả lời từ trí nhớ thay vì gọi tool.
- ❌ Chỉ gọi 1 tool rồi kết luận — phải orchestrate (list + search + describe).
- ❌ Lấy top-1 result làm sự thật.
- ❌ Gộp KHLCNT/TBMT/LCNT/E-HSMT thành "hồ sơ".
- ❌ Kết luận trạng thái khi không có mốc thời gian / `status`.
- ❌ Cite chung chung "theo hồ sơ" — phải đủ `entity_code + source_file + page`.
- ❌ Bỏ trống `page` thay vì ghi `page=không có trong metadata`.
- ❌ Suy diễn cross-doc link mà không gắn `link_status=inferred` + cảnh báo.
- ❌ Skip "cần kiểm tra thêm" để ra kết luận mạnh khi cite yếu.
- ❌ Chuyển "không thấy trong nguồn" thành "không có" trong gói thầu.
- ❌ Tạo section ngành riêng (vd. "phân tích y tế").
- ❌ Render full 5-part cho discovery query (chỉ candidate table + summary trừ khi user yêu cầu rõ).
- ❌ Mở rộng keyword ngành bằng synonym mà không log keyword đã dùng.