# HANDOFF REPORT: M4 WEB UI & VERSIONING GOVERNANCE INVESTIGATION

**Agent**: teamwork_preview_explorer (M4 Web UI & Versioning Governance Specialist 3)  
**Date**: 2026-10-08T07:42:00Z  
**Recipient**: Parent Orchestrator (`f9992164-c0e4-4f7d-ba4a-25a83a4436bf`)  
**Milestone**: M4 (Web Review Studio & Multi-worker UI Governance)  
**Type**: Hard Handoff (Investigation & Architecture Proposal Complete)  

---

## 1. Observation

### Obs 1: Kiến Trúc Frontend và Phân Vùng Tệp Tin Web Review Studio
- `c:\Projects\KieuStory\web_review\templates\index.html`:
  * Tệp duy nhất chứa 2,053 dòng mã (71,399 bytes). Toàn bộ CSS, HTML và JS đều được tích hợp trong file này, không có thư mục `static/` phụ trợ.
  * Hệ thống Tab điều hướng hiện có (dòng 998-1004): 5 tab (`videos`, `file-manager`, `characters`, `scripts`, `prompts`).
  * Khung trình phát video chính (`#main-player`, dòng 1015) có chức năng chuyển đổi tỷ lệ khung hình thích ứng (16:9 Cinema Wide vs 9:16 Shorts).
  * Modal lightbox duy nhất hiện có là `#image-modal` (dòng 1266-1273) chuyên dùng để xem ảnh phóng to Concept Art 32 nhân vật. **Hoàn toàn không có Shot Detail Modal**.
- `c:\Projects\KieuStory\web_review\server.py`:
  * Mounts static: `/assets/videos` (189 file), `/assets/characters`, `/assets/keyframes` (169 tail frames `clean_frame_239.jpg`), `/assets/exports` (master cuts).
  * API endpoints đã đăng ký: `/api/library`, `/api/videos`, `/api/characters`, `/api/prompts`, `/api/shots`, `/api/scenes`, `/api/episodes`, `/api/episode/{filename}`, `/api/status`, `/api/generate`.
  * **Chưa có endpoint `/api/concat`**.
  * **Chưa có endpoint nạp hay trả về `gemini_banana_prompts.json`**. Biến `PROMPTS_FILE` tại dòng 25 chỉ đọc duy nhất `muse_ai_video_prompts.json`.

### Obs 2: Ma Trận 188 Shots EP01 và Đối Soát Hiển Thị
- Cơ sở dữ liệu prompt:
  * `02_AI_Prompts/gemini_banana_prompts.json`: Chứa chính xác 188 shots EP01 từ `ep01_scene01_shot01` đến `ep01_scene15_shot06` (kèm độ phân giải chuẩn `"1280x720"`, `character_anchor`, `environment_anchor`, và prompt Sweet-Spot).
  * `02_AI_Prompts/muse_ai_video_prompts.json`: Chứa chính xác 188 shots EP01 trong `motion_prompts`, phân bổ trên 15 phân cảnh:
    `ep01_scene01` (21 shots), `ep01_scene02` (15 shots), `ep01_scene03` (15 shots), `ep01_scene04` (12 shots), `ep01_scene05` (27 shots), `ep01_scene06` (14 shots), `ep01_scene07` (8 shots), `ep01_scene08` (8 shots), `ep01_scene09` (6 shots), `ep01_scene10` (14 shots), `ep01_scene11` (10 shots), `ep01_scene12` (8 shots), `ep01_scene13` (12 shots), `ep01_scene14` (12 shots), `ep01_scene15` (6 shots). Tổng = 188 shots.
- Hành vi thực tế trên UI:
  * Tab 1 (`raw_shots` accordion, dòng 1724-1797): Dữ liệu được sinh động từ `all_raw = list(VIDEOS_DIR.glob("*.mp4"))` trong `server.py` dòng 93. Do thư mục `04_Assets/videos` hiện mới có 71 file EP01 (48 shot đơn lẻ), nên **140 shot chưa render bị biến mất hoàn toàn trên UI**.
  * Tab 5 (`prompts-list`, dòng 1955-1983): Đổ toàn bộ 1,149 prompt thành danh sách phẳng, không phân chia theo 15 cảnh của Tập 1.

### Obs 3: Kiểm Chứng Audio Guard và Khóa Khẩu Hình (Lip-Sync Guard)
- Audio Guard:
  * Chuỗi bắt buộc: `"Âm thanh: ... Quy tắc âm thanh: Tuyệt đối KHÔNG sinh nhạc nền (no music/BGM), không âm thanh điện tử, không tạp âm rè nhiễu. Chỉ sinh âm thanh môi trường tự nhiên (foley, ambience) và thoại nhân vật chân thực."` có mặt 100% trong 188 prompt của `muse_ai_video_prompts.json`.
  * Trên UI: Chỉ hiển thị dạng text thô trong Tab 5, không có huy hiệu bảo vệ âm thanh (Audio Guard Badge) hay khung cảnh báo âm lượng EBU R128 (-14 LUFS).
- Lip-Sync Closed Lips Guard:
  * Chuỗi bắt buộc: `"[KHÓA KHẨU HÌNH BẮT BUỘC / LIPS CLOSED]: Đôi môi nhân vật trong khung hình khép chặt tự nhiên khi nghe tiếng gọi từ xa hoặc giọng dẫn chuyện V.O. (lips closed), tuyệt đối không mấp máy."` có mặt tại các shot có thoại ngoài khung hình (off-screen/V.O.).
  * Trên UI: Hoàn toàn không có cờ/badge hay bộ lọc phát hiện cử động môi khép.

### Obs 4: Quy Chuẩn Đặt Tên Versioning `_v<N>`
- `05_Production_Pipeline/run_shot.py` dòng 101-113: Đã áp dụng `pattern = re.compile(rf"^{re.escape(shot_id)}_10s(?:_v(\d+))?\.mp4$", re.IGNORECASE)` và tự động tăng `_v{next_v}.mp4`.
- `05_Production_Pipeline/production_orchestrator.py` dòng 350-363: Đã có `resolve_versioned_path` sinh `_v1.mp4`, `_v2.mp4` và ưu tiên bản version cao nhất trong `find_rendered_video`.
- Tuy nhiên trong `web_review/server.py` (dòng 303-310): Chưa có regex bóc tách version `_v(\d+)`. Các bản re-take (`_v2.mp4`) bị gán cùng tiêu đề hiển thị như `_v1.mp4`, và trình phát video không hiển thị huy hiệu version.

### Obs 5: Trạng Thái Milestones trong `PROJECT.md`
- `c:\Projects\KieuStory\PROJECT.md`:
  * Dòng 49: `| M3 | 4-Stem Audio Engine & Ambience Continuity | ... | M1 | IN_PROGRESS |`
  * Dòng 50: `| M4 | Web Review Studio Sync & Production Integration | ... | M2, M3 | PLANNED |`
- Worker M3 (`.agents/teamwork/worker_m3_1/handoff.md`) đã nộp Hard Handoff hoàn thành 100% công việc của Milestone 3 vào lúc 2026-10-08T07:16:00Z.
- Toàn bộ test suite (`pytest tests/ -v`) đạt kết quả **173 passed, 0 failures, 0 errors** (100% PASS).

---

## 2. Logic Chain

1. **Từ Obs 1 và Obs 2**: Vì `index.html` chỉ render các shot từ `lib.raw_scenes` (vốn chỉ quét các file mp4 đang tồn tại trong `04_Assets/videos`), nên 140/188 shots của EP01 chưa được hiển thị. Để đạo diễn và tester theo dõi được toàn diện 188 shots trên 15 phân cảnh, UI bắt buộc phải có một view chuyên biệt ("Ma Trận 188 Shots (EP01)") nạp trực tiếp danh mục 15 cảnh từ kịch bản/prompts bất kể file video đã render hay chưa.
2. **Từ Obs 1 và Obs 3**: Do `server.py` không nạp `gemini_banana_prompts.json` và `index.html` không có Shot Detail Modal, nên người dùng không có cách nào xem Start Frame 720p prompt, Audio Guard hay Lip-Sync Guard của từng shot. Cần bổ sung Shot Detail Modal hai cột (Cột trái: Media Preview; Cột phải: 3 Tiers Prompts & Guards).
3. **Từ Obs 4**: Vì `run_shot.py` và `production_orchestrator.py` đã tạo ra các file versioned `_10s_v1.mp4`, `_v2.mp4`, `_master_v1.mp4`, nhưng `server.py` và `index.html` chưa parse trường `version`, dẫn đến nguy cơ xung đột hiển thị các bản re-take. Cần bóc tách `_v(\d+)` và gắn huy hiệu `v1`, `v2` trên thẻ video và VIP Cinema Player.
4. **Từ Obs 5**: Vì Milestone 3 đã hoàn tất nghiệm thu và toàn bộ 173 test cases đã pass, bảng Milestones trong `PROJECT.md` cần chuyển M3 sang `DONE` và M4 sang `IN_PROGRESS`.

---

## 3. Caveats

- **Phạm vi khảo sát**: Phân tích tập trung vào frontend `index.html` và tầng giao tiếp API của `web_review/server.py`. Không can thiệp trực tiếp vào mã nguồn sản xuất (`web_review/`, `PROJECT.md`) theo đúng quy tắc Read-Only Investigation của Agent Archetype explorer.
- **Backend Dependency**: Để Ma Trận 188 Shots và Shot Detail Modal hoạt động tối ưu nhất, Worker M4 nên kết hợp triển khai endpoint `GET /api/matrix/ep01` và `POST /api/concat` trong `server.py` (như đã phân tích tại `analysis.md` và mã đề xuất `proposed_frontend_enhancements.js`). Trong trường hợp backend chưa kịp cập nhật, frontend có thể sử dụng cơ chế Client-Side Fallback tổng hợp từ `/api/shots` và `/api/library`.

---

## 4. Conclusion

1. **Khẳng định tính tương thích**: Ma trận 188 shots của EP01 phân bố chuẩn xác trên 15 phân cảnh (C01 - C15), khớp 100% giữa kịch bản `FilmMaker/TAP_01_*.md`, `gemini_banana_prompts.json` và `muse_ai_video_prompts.json`.
2. **Khoảng cách cần đóng (Gaps)**:
   - Giao diện thiếu tab "Ma Trận 188 Shots (EP01)" hiển thị trạng thái hoàn thành từng shot theo 15 cảnh.
   - Giao diện thiếu "Shot Detail Modal" hiển thị đồng thời 3 tầng prompt (Banana 720p, Muse motion, Audio Guard) và huy hiệu Khóa Khẩu Hình (Closed Lips Guard).
   - Giao diện chưa phân biệt rõ ràng các phiên bản versioning `_v1`, `_v2` trên thẻ và player.
   - Thiếu nút bấm tương tác kích hoạt ghép Master Cảnh (`/api/concat`) trực tiếp từ giao diện.
3. **Cập nhật Milestone**: Đề xuất cập nhật ngay `PROJECT.md` dòng 49-50: M3 -> `DONE`, M4 -> `IN_PROGRESS`.
4. **Bàn giao mã nguồn**: Toàn bộ mã HTML/CSS/JS mẫu chi tiết đã được soạn thảo sẵn sàng tại `.agents/teamwork/explorer_m4_3/proposed_frontend_enhancements.js`.

---

## 5. Verification Method

Để kiểm chứng độc lập báo cáo này:

1. **Kiểm tra bộ dữ liệu 188 shots EP01**:
   ```powershell
   python -c "import json; b = json.load(open('02_AI_Prompts/gemini_banana_prompts.json', encoding='utf-8')); m = json.load(open('02_AI_Prompts/muse_ai_video_prompts.json', encoding='utf-8')); print('Banana EP01:', len([k for k in b if k.startswith('ep01_scene')])); print('Muse EP01:', len([k for k in m['motion_prompts'] if k.startswith('ep01_scene')]))"
   ```
   *Kết quả kỳ vọng*: Cả hai đều in ra chính xác `188`.

2. **Chạy toàn bộ Test Suite Tiers 1-4**:
   ```powershell
   pytest tests/ -v
   ```
   *Kết quả kỳ vọng*: `173 passed` (100% pass).

3. **Kiểm tra tệp đề xuất giao diện**:
   Mở tệp `c:\Projects\KieuStory\.agents\teamwork\explorer_m4_3\proposed_frontend_enhancements.js` để đối soát cấu trúc DOM và logic JavaScript cho Worker M4.
