# 🚀 DOING: Ultra × Outfit Join

## 📌 Context
- **Idea:** `plan/ideas/04_size_guide_injection.md`
- **Status:** ✅ Done

## 🎯 Goal
Refactor `_enrich_with_outfit()` để đọc `ultra_descriptions.ai_matches` (occasion-aware, kèm name/color/image/reason) thay vì `ai_outfit_product_matches`, rồi inject `clean_description` vào từng SP để Responder có đủ context tư vấn.

## ⚠️ Active Trade-offs
- **Fallback giữ nguyên:** Nếu `ai_matches` null → vẫn dùng `ai_outfit_product_matches` cũ
- **`base_ref_code` normalize:** magento_ref_code "5BP25W003-SK010" → base "5BP25W003" để join ultra_desc
- **clean_description truncate:** Chỉ lấy 800 chars đầu tránh token explosion

## 🛠 Impact & Files Touched
| File | Symbol | Change | Blast Radius |
|------|--------|--------|--------------|
| `agent/tag_search_agent_v2/tag_search_tool.py` | `_enrich_with_outfit()` | MODIFY | 1 caller (tag_search_tool) |
| `agent/tag_search_agent_v2/tag_search_tool.py` | `_format_products()` | MODIFY | 1 caller |
| `agent/tag_search_agent_v2/tag_search_tool.py` | `TAGS_TO_OCCASION` | ADD | 0 |
| `agent/tag_search_agent_v2/tag_search_tool.py` | `_resolve_occasion()` | ADD | 1 caller |

**Risk:** Low — refactor in-place, fallback đảm bảo không break

## 🔙 Rollback Plan
N/A — Risk thấp, fallback về code cũ tự động khi `ai_matches` null

## 📋 Execution Checklist

### Phase 1: Fix DB path + thêm TAGS_TO_OCCASION + _resolve_occasion (~15 phút)
- [x] Task 1.1: Sửa `db_123_path` trỏ đúng `backend/123.db` (hiện đang trỏ `worker/123.db` → sai)
- [x] Task 1.2: Thêm constant `TAGS_TO_OCCASION` mapping occ: tags → occasion key
- [x] Task 1.3: Thêm hàm `_resolve_occasion(tags) -> str`

### Phase 2: Refactor `_enrich_with_outfit()` (~30 phút)
- [x] Task 2.1: Thay query `ai_outfit_product_matches` → query `ultra_descriptions` lấy `ai_matches + clean_description`
- [x] Task 2.2: Normalize base_ref_code từ magento_ref_code (split "-" lấy phần đầu)
- [x] Task 2.3: Parse JSON `ai_matches`, chọn occasion đúng, build `match_codes`
- [x] Task 2.4: Batch query StarRocks lấy price/url cho match_codes
- [x] Task 2.5: Stock check match products, build output với đầy đủ fields
- [x] Task 2.6: Inject `clean_description` (800 chars) vào anchor product

### Phase 3: Update `_format_products()` + output (~10 phút)
- [x] Task 3.1: Thêm `clean_description` vào formatted item
- [x] Task 3.2: Thêm `occasion_used` vào JSON output của tool

### Phase 4: Smoke test (~5 phút)
- [x] Task 4.1: Restart server → query "áo phông trắng đi chơi" → kiểm tra `ai_outfit_suggestions` có `role, reason, occasion`
- [x] Task 4.2: Query không có occ: tag → kiểm tra fallback `hang_ngay`
- [x] Task 4.3: Kiểm tra `clean_description` có trong output

## 🔄 Sub-Doings
_None yet_

## ✅ Completion Gate
- [x] All tasks [x] | [x] Sub-Doings resolved | [x] Smoke test passed | [x] Trade-offs confirmed

---
_Started: 2026-04-28 | Updated: 2026-04-28_
