visionA/docs/autoflow/04-architecture/review/phase-0.8-cross-review.md
jim800121chen fb7da5d180 chore(autoflow): migrate .autoflow/ 共享層文件至 docs/autoflow/
依 autoflow-agent workspace v2 設計把 PRD / 設計 / 架構 / 交付類
共享文件從個人層 .autoflow/(ignored)搬到 docs/autoflow/(進 git),
讓團隊可共享產品與架構文件,個人層只留 progress / review / testing 等
per-branch 筆記。

- 02-prd/        21 個檔(PRD、features、market-analysis 等)
- 03-design/     18 個檔(design-spec、wireframes、flows 等)
- 04-architecture/ 31 個檔(TDD、design-doc、ADR×14、API 規格等)
- 07-delivery/   3 個檔(project-summary、phase-0.6-handover、stage-deployment-setup)

合計 73 檔。原檔已從 .autoflow/ 移除(migration 工具執行 git mv,
但因 .autoflow/ 在 .gitignore 中、git 將此操作視為新增、無 rename history)。
2026-05-04 16:55:55 +08:00

481 lines
26 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Phase 0.8 三方交叉審閱 — Architect 視角
> **作者**Architect Agent
> **日期**2026-04-30
> **審閱對象**PM PRD`feature-converter-integration.md`、Design wireframe`wireframe-conversion.md`、Design flow`flow-conversion.md`
> **對照基準**Architect ADR-014 v1.1、`conversion.md` v0.3、`api/api-conversion.md` v0.3
---
## 摘要
| 對象 | 嚴重 | 中 | 小 / nit |
|------|-----|----|---------|
| PM PRD | 1 | 4 | 2 |
| Design wireframe | 1 | 2 | 2 |
| Design flow | 1 | 1 | 1 |
> **嚴重 = 直接導致實作有歧義或 frontend / backend 對不上**;中 = 文件不精確但可推測;小 = 命名 / 措辭。
**Architect 自己的 TDD 修訂**4 個章節(議題 #2 / #5 / #6 / #7)已寫進 `conversion.md` v0.3 + `api/api-conversion.md` v0.3。詳見 §3。
**需要使用者裁決的事項**1 件API endpoint 路徑命名 — `/api/conversion/*` vs `/api/converter/jobs/*`,目前三方文件不一致)。
---
## 1. 對 PM PRD 的審閱(`02-prd/features/feature-converter-integration.md`
### 1.1 ✅ 同意的部分
- **§1 概要 / §2 User Stories**MVP 範圍清楚,半自動設計理由明確
- **§3 F1F5 的功能定義**:與我 TDD 的 endpoint 行為對齊status enum、510s polling、500MB cap、ref images 上限、translated error messages
- **§4 非功能需求**500MB / 10MB / 100 張上限、polling 間隔、active job 限制 — 全部已在 TDD §4 / §9 / §10 cover
- **§5 Non-Goals**:完整且符合 MVP 邊界(不做歷史 / 取消 UI / SSE / 多 chip
- **§6 整合決策 D1D6**:與 ADR-014 完全一致streaming proxy / FAA 直連 / 半自動 / polling / converter API 不動 / sidebar 獨立 tab
- **§7 Dependency 一覽**:清楚標出 converter / FAA / MC / visionA-backend / visionA-frontend 各自要做什麼
- **§9 驗收條件**:可測、與 TDD 行為對齊
- **§11 給 Architect 的注意事項**streaming proxy 用 `io.Pipe` 不 buffer 全 RAM、user-scoped 授權、idempotent promote — 全部已落地
### 1.2 ⚠️ 嚴重 — API endpoint 路徑命名與 TDD 不一致
**位置**PRD §F6 / §F7
```
PRD §F6POST /api/converter/jobs/{id}/import-to-models
PRD §F7POST /api/converter/jobs/{id}/download-token
Wireframe §3.3 / Flow §3GET /api/converter/jobs/active
Wireframe §6.3GET /api/converter/jobs/{id}polling
TDDArchitect
POST /api/conversion/init
GET /api/conversion/{job_id}
POST /api/conversion/{job_id}/promote-to-models
GET /api/conversion/{job_id}/download ← 注意:是 GET、不是 POST `/download-token`
GET /api/conversion/active
```
**三個衝突點**
1. **path prefix**`/api/converter/jobs/*`PM/Designvs `/api/conversion/*`Architect
2. **action 命名**`import-to-models`PMvs `promote-to-models`Architect
3. **download endpoint method + 形式**PRD/Design 假設 `POST /download-token``{url, expires_at}` JSONTDD 已改為 `GET /download` server-side 302 redirectADR-014 v1.1 議題 #9 已決議的安全升級)
**建議改法**
採 Architect 的版本(`/api/conversion/*` + `promote-to-models` + `GET /download` 302— 理由:
- 路徑前綴 `/conversion/` 對應 visionA 內部模組名(`internal/conversion/`),命名一致
- `/converter/jobs/*` 容易讓人誤以為是「轉發給 converter 的 raw API」其實 visionA backend 有自己的 ownership / 半自動邏輯,不是純 proxy
- `promote-to-models` 對齊 converter 的 `/promote` 動詞、語意精確
- `GET /download` + 302 已在 ADR-014 v1.1 完成決策(安全考量壓倒 UX 微差)
**請 PM 修**(新增到 §1.3 PM 修訂建議清單):
- §F6 endpoint 改 `POST /api/conversion/{job_id}/promote-to-models`
- §F7 endpoint 改 `GET /api/conversion/{job_id}/download`server 302 redirect+ 移除「visionA backend 跟 Member Center 換 delegated download token」的描述這仍正確但藏在 server-side把「回傳 `{url, expires_at}`」改為「browser 自動 follow 302 直連 FAA」
**請 Design 修**(同節 §2.2
- wireframe §3.3、wireframe §6.3、flow §3 / §5.5 / §8.2 全部 `/api/converter/jobs/*``/api/conversion/*`
- flow §3 sequence diagram 的 download 那段 `POST /api/converter/jobs/{id}/download-token` + `200 { url, expires_at }``GET /api/conversion/{id}/download` + `302 Location: faa-url`
- wireframe §7.2「下載」流程描述:移除「拿到 `{ url, expires_at }`」,改為「按鈕觸發 anchor click 或 `window.location.href = '/api/conversion/{id}/download'`browser 自動處理 302」
### 1.3 ⚠️ 中 — Active job 端點未列入 PRD
**位置**PRD §F 段(功能需求)
PRD §F1F7 沒有列出「Active job pre-check」這個功能但 §3 F3 隱含提到「同 user 同時只能跑一個 active job」。Design wireframe §3.3 與 flow §5.1 明確使用 `GET /api/converter/jobs/active`(建議改名 `/api/conversion/active`)做 idle / 重新整理 / 多分頁的恢復邏輯。
**建議**PRD §F 段補一條 F0
```markdown
### F0進入「轉檔」頁面時的 active job 偵測
- 進入 /conversion 時前端打 GET /api/conversion/active
- 後端回應 `{ has_active: bool, job? }`
- has_active=true → 直接顯示「進行中」畫面(同 F3+ banner「您離開前的轉檔仍在進行中」
- has_active=false → 顯示空狀態 + CTA
```
理由:這個端點是 wireframe 的核心§3.3、§6.4 多分頁同步、§6.6 重啟頁面恢復),在 PRD 沒列就成了「設計依賴的隱形 contract」三方對齊時容易遺漏。
### 1.4 ⚠️ 中 — Streaming upload 進度語意未明示
**位置**PRD §F2「上傳行為」、§F3「轉檔執行與進度」
PRD §F2 寫「使用者看到的是『上傳到 visionA』的單一進度條XHR upload event」— 這裡有歧義:
- **語意 A**XHR `upload.onprogress` 顯示 browser → backend 的進度。當 browser send 完 100% 後backend 還在 forward 給 converter 的階段,前端顯示什麼?
- **語意 B**:「上傳到 visionA」= browser → backend 的單一進度,使用者看到 100% 就視為完成
實作上若採 B則 backend 需要 background goroutine + 額外 ownership 狀態(`upload_in_progress`)才能 early-return採 A 則 backend 等 converter 201 才回 200前端進度顯示 100% 後到實際切 processing 之間有 1-3 秒「即將完成…」/「伺服器處理中…」。
**TDD 採用語意 A**(見 `conversion.md` §4.3.1 v0.3 新增)— 理由:
- 100% 接近端到端真實狀態,使用者不會被欺騙
- 實作簡單,失敗處理路徑清楚
- 1-3 秒延遲對 500MB 上傳體感影響極小
**建議 PM 補在 §F2 / §F3**
```markdown
> **進度條語意說明**:上傳進度條顯示 browser → visionA-backend 的進度。當顯示 100% 但
> backend 還在轉發給 converter 時,文案會切為「即將完成…」/「伺服器處理中…」13 秒),
> 然後才切到「轉檔進行中」畫面。對使用者誠實 — 不謊報已完成。
```
### 1.5 ⚠️ 中 — Promote-to-models request body 對齊 Design
**位置**PRD §F6「加到模型庫」流程
PRD §F6 沒有提到「需要使用者輸入名稱」,但 Design wireframe §7.1 設計了 import Dialog 含名稱輸入欄。我這邊 API specv0.3)已對齊 Design 的「單欄位 name only」決議。
**建議 PM 補在 §F6**
```markdown
- 點「加到模型庫」開確認 Dialog單欄位
- 模型名稱(預設 `{source_filename_stem}_{target_chip.lower()}`,可改)
- 描述欄位 Phase 1 才開放
- 確認後呼叫 POST /api/conversion/{id}/promote-to-models
```
或在 §F6 末尾加註「Dialog UI 與欄位定義詳見設計規格 wireframe §7.1。」
### 1.6 ⚠️ 中 — visionA-backend 重啟後的 UX
**位置**PRD §11 給 Architect 的注意事項 / 應該補在 §6 整合決策或 §F0
PRD 沒有討論 visionA-backend 重啟部署、crash recovery後使用者 UX 該怎樣。我 TDD §2.6.1 v0.3 補了 lazy rebuild 機制A4 方案 — `/active` 端點 fallback 對 converter 查 `?user_id=&status=in_progress`),讓使用者重啟後仍能看到自己的 active job。
**這需要 converter Phase 1 提供 `GET /api/v1/jobs?user_id=&status=in_progress` endpoint**converter Phase 1 已實作,但 PRD §7 dependency 表未列入「visionA 會用此 endpoint」
**建議 PM 補在 §7 Dependency 表**
```markdown
| kneron_model_converter | ❌ 完全不用動 | 沿用既有 endpoint`POST /api/v1/jobs``GET /api/v1/jobs/{id}``POST /promote``GET /api/v1/jobs?user_id=&status=in_progress`visionA-backend 重啟後 lazy rebuild ownership 用)、`POST /api/v1/jobs/{id}/cancel`visionA-backend 偵測 client disconnect 時內部 cleanup 用) |
```
**也建議在 §6 整合決策表加一條 D7**
```markdown
| D7 | visionA-backend in-memory ownership 重啟遺失 | Phase 0.8 採 lazy rebuild`/active` fallback 對 converter 查Phase 0.9+ 評估 DB persist | converter 7 天 expires_at 兜底UX 上使用者重進頁面仍看得到 active job |
```
### 1.7 小 — KPI「上傳到拿 NEF P95 < 10 分鐘」量測點
**位置**PRD §8 KPI
PRD §8 寫「visionA backend 在 import / download 觸發點 log timestamp」— 但 import/download 是「使用者拿到 NEF 後的下一步」,不是「拿到 NEF 的當下」。建議改:
- 量測點 = converter status 從 `running``succeeded` 的當下時間 - `init` 收到 request 的時間
- 這是 backend 視角的端到端時間,不依賴使用者按按鈕
非阻擋議題,建議調整。
### 1.8 小 — 4 個 chip 數量
PRD §F2 寫「目標 chipKL520 / KL630 / KL720 / KL730」4 個),但 TDD `api-conversion.md` §1 與 converter `platform` 欄位的 enum 寫的是 `520 / 720`2 個)。需確認:
- converter Phase 1 實際支援哪幾個 platform
- 如果只支援 520 / 720PRD 應改為 2 個(避免使用者選了 630/730 然後被 converter 拒絕)
- 如果 converter Phase 1 已擴充到 4 個TDD `platform` enum 應改為 `520 / 630 / 720 / 730`
**建議 PM**:請與 converter 團隊確認 Phase 1 實際支援的 chip listPRD 與 TDD 同步更新。
---
## 2. 對 Design 的審閱
### 2.1 對 Wireframe`03-design/wireframes/wireframe-conversion.md`
#### 2.1.1 ✅ 同意的部分
- **§0 設計對齊備註**:複用既有元件、不新增 Design Tokens、走 i18n — 全部對的方向
- **§1 Sidebar 進入點**放模型庫之後心智模型清楚Wand2 icon 選擇合理
- **§2 頁面狀態總覽**state 機切 4 種畫面,無 URL query state — 簡潔正確
- **§3.3 邊界 — 已有 active job**:用 `GET /jobs/active` 做進入恢復是正確的設計(解決多分頁 / 重新整理 / 重啟)
- **§4 Upload Dialog**階段切換select / uploading合理§4.4 上傳失敗的 4 種 case 完整
- **§5 主畫面 vs Dialog 進度**分開顯示避免使用者困惑、tab title 動態更新
- **§6 Processing 畫面**3-stage indicator 設計、indeterminate progress、polling 間隔5s 前 60 秒、之後 10s— 都與 TDD 對齊
- **§6.4 邊界情境**4 種情境(關分頁、多分頁、長排隊、長執行)有 cover
- **§7 Success 結果**:兩按鈕互不互斥 / 過期倒數 / 「開始新轉檔」放外面 — 與 PRD §F4 對齊
- **§8 Failed 狀態 + suggestions**:依 error code 切換建議很棒
- **§8.2 Job 已過期**:對 TDD `expires_at` 機制依賴正確
- **§9 響應式 / §11 i18n / §12 無障礙**:全部到位
#### 2.1.2 ⚠️ 嚴重 — endpoint 路徑與 TDD 不一致
同 §1.2。請改 `/api/converter/jobs/*``/api/conversion/*``POST /download-token` 形式 → `GET /download` + 302 redirect。
具體要改的位置:
- §3.3 邊界表「`GET /api/converter/jobs/active`」 → `GET /api/conversion/active`
- §6.3 polling 表「端點 `GET /api/converter/jobs/{id}`」 → `GET /api/conversion/{id}`
- §7.1 「呼叫 POST /api/converter/jobs/{id}/import-to-models」 → `POST /api/conversion/{id}/promote-to-models`
- §7.2 整段流程:去掉 `POST /download-token` + 拿 `{ url, expires_at }` → 改為 anchor tag 觸發 `GET /api/conversion/{id}/download`browser 自動 follow 302
§7.2 流程修改範例:
```diff
- 1. 點擊 → 按鈕進 loading 狀態spinner + 「準備下載…」)
- 2. 呼叫 POST /api/converter/jobs/{id}/download-token
- 3. 200 OK
- - 拿到 { url, expires_at }
- - 立即 window.location.href = url瀏覽器內建下載管理器接手
- - 按鈕回到原狀態(不變灰,使用者可重複下載)
+ 1. 點擊 → 觸發 anchor 行為 / window.location.href = '/api/conversion/{id}/download'
+ 2. visionA-backend server-side 302 → browser 自動 follow → 直連 FAA
+ 3. 按鈕不需 loading 狀態navigation 由 browser 接管)
+ 若需要錯誤處理(例 job_not_completed可改用 fetch + 檢 302 status
```
> **附註**:這個改動實際上「簡化」了 Design 的 §7.2 描述(不用處理 token、不用 fetch then redirect— 是 ADR-014 v1.1 帶來的好處。
#### 2.1.3 ⚠️ 中 — Stage indicator 對應實際狀態
**位置**wireframe §6.1 「Stage 對應」表
Design 把 converter 的 `running` 狀態切成兩個視覺 stage「解析模型」、「編譯 NEF」純粹是 UI 上的分段,不對應 converter 內部真實階段。
**問題**converter Phase 1 的 `GET /api/v1/jobs/{id}` response 其實有 `stage` 欄位(`onnx` / `bie` / `nef`,見 api-conversion.md §2 Job response這比 wireframe 假設的「單一 running 狀態」更精細。
**建議**
- **選項 A**wireframe 的 3-stage 對應到 converter `stage` 欄位(`onnx` → 解析、`bie` → 量化、`nef` → 編譯),這樣 stage indicator 是真實狀態而不是視覺 fake
- **選項 B**維持現狀fake stage— 簡單但不夠誠實
**Architect 建議選項 A**。理由converter `stage` 已經提供 — 不利用反而浪費。具體 mapping
| converter stage | UI stage 名稱 | 觸發條件 |
|----------------|------------|---------|
| `onnx` | 解析模型 | converter status=running, stage=onnx |
| `bie` | 量化模型 | converter status=running, stage=bie |
| `nef` | 編譯 NEF | converter status=running, stage=nef |
stage 名稱建議改為 3 個:「解析」/「量化」/「編譯」(更貼近 converter 實際做的事)。
**請 Design 對齊 + 改 §6.1**:把 stage 名稱與 converter `stage` 欄位 mapping並更新 wireframe §11.6 i18n key。
#### 2.1.4 ⚠️ 中 — Upload XHR 進度 100% 後的文案
**位置**wireframe §4.2 階段 B「上傳中」
wireframe §4.2 設計「進度條 + 預估剩餘」,但沒明確規定 XHR `loaded === total` 後但 backend 還沒回 200 的這 1-3 秒要顯示什麼。flow §5.3 有提到「即將完成…」/「伺服器處理中…」— 這需要在 wireframe 對齊:
**建議**wireframe §4.2 加註:
```markdown
**進度 100% 後但伺服器還沒回**
| XHR 狀態 | 文案 |
|---------|-----|
| progress < 100% | 已上傳 X / Y · 預估剩餘 N |
| progress = 100%, 等待 < 5 | 即將完成 |
| progress = 100%, 等待 5 | 伺服器處理中 |
```
對應 i18n key§11.5)已有 `conversion.uploading.almostDone`,建議再加 `conversion.uploading.serverProcessing`
#### 2.1.5 小 — 「加到模型庫」按鈕 vs Dialog 確認
wireframe §7.1 設計了確認 Dialog複用 import flow— 在 §14 給 PM 的補充第 1 條已正確標記為「待 PM 決定」。
**Architect 立場**:保留 Dialog 是對的model record 是永久資源、使用者控制名稱比較自然)。已在 TDD api-conversion.md v0.3 的 promote-to-models request body 對齊「單欄位 name only」。
#### 2.1.6 小 — Wand2 icon 替代
§10 給的替代方案合理FileCog / Replace不是 Architect 領地,由 Design / 使用者決定。
### 2.2 對 Flow`03-design/flows/flow-conversion.md`
#### 2.2.1 ✅ 同意的部分
- **§3 全景圖Mermaid**:完整且與 ADR-014 對齊,包含所有 5 個 stageactive check / select / uploading / processing / completed
- **§4 State Machine + 5 狀態保存策略**:「不持久化 jobId 全部由 backend `/active` 提供」是核心原則,正確
- **§5.4 Polling 策略**visibilitychange 暫停、退避、終止條件 — 全部與 TDD §9 對齊
- **§6 邊界情境**6.1 active job、6.2 上傳失敗、6.3 過期、6.4 多分頁、6.5/6.6 重新整理 — 全部 cover
- **§7 UX Writing 要點**:誠實呈現狀態、避免技術語 — 對齊 design-spec
- **§8.2 給 Architect 的補充**5 條建議,第 1/2/3/4/5 條我都已採納並補進 TDD謝謝
#### 2.2.2 ⚠️ 嚴重 — endpoint 路徑與 TDD 不一致
同 §1.2 / §2.1.2。具體位置:
- §3 全景圖 sequence diagram 中所有 `POST /api/converter/jobs` / `GET /api/converter/jobs/{id}` / `POST /api/converter/jobs/{id}/promote-to-models` / `POST /api/converter/jobs/{id}/download-token` → 全部改 `/api/conversion/*` 前綴
- §3 stage 3b sequence diagram「下載」那段 `POST /api/converter/jobs/{id}/download-token` + 「`{ url, expires_at }`」→ `GET /api/conversion/{id}/download` + `HTTP 302 Found, Location: faa-url`
- §5.5 「下載」分支步驟 1-4 改成 anchor 觸發、browser 自動 302 follow
- §8.2 給 Architect 第 1 條建議端點名稱
修法同 §2.1.2。
#### 2.2.3 ⚠️ 中 — Cancel 後 backend 對 converter 的 cleanup
**位置**flow §5.3「取消」末尾、§8.2 給 Architect 第 4 條
flow §5.3 寫「visionA backend 收到取消信號後**也要對 converter 發 cancel**(避免孤立 job」— 我在 TDD `conversion.md` §4.3.2 v0.3 補了完整的 cleanup 鏈分析C1C4 情境表 + best-effort cancel via `POST /api/v1/jobs/{id}/cancel`)。
Design 的這段描述沒問題,但**沒講清楚** converter 是否提供 cancel endpoint。事實上 converter Phase 1 已實作 `POST /jobs/{id}/cancel`PRD §5 N2 提到),但 PM Phase 0.8 Non-Goals 把「使用者主動取消」列在 N2。
**澄清**「使用者主動取消」PM 不做)≠ 「backend 內部 best-effort cancel 做 cleanup」TDD 做)。前者是 UI feature、後者是 reliability infra。兩者用同一個 converter endpoint 但語義不同。
**建議 Design**:在 flow §5.3「取消」末尾加註:
```markdown
> **澄清**:使用者按「取消上傳」是 frontend 端的 `xhr.abort()`TCP RST 觸發 backend
> cleanup 鏈backend 內部會 best-effort 對 converter 發 cancel。這個 cancel **是內部
> 韌性處理**,不暴露 UIPRD Phase 0.8 Non-Goals N2 講的是「進行中 job 的取消 UI」
> 兩者不衝突。
```
#### 2.2.4 小 — `expires_at` 來源 + frontend 顯示
flow §5.5 success 階段「過期提醒」描述:
> 計算 `expires_at - now()` → 顯示「6 天 21 小時後自動清除」
正確,且 TDD api-conversion.md v0.3 已確保 `expires_at` 在 Job response 必出現(無論 converter 給或 backend 推算)。✅ 對齊。
---
## 3. Architect 自己的 TDD 修訂(這次補上的)
### 3.1 議題 #2 — visionA backend 重啟後 ownership 全失
**修訂**`conversion.md` §2.6.1(新增)
採方案 **A4lazy rebuild**`/active` endpoint 在 in-memory miss 時fallback 對 converter 查 `GET /api/v1/jobs?user_id=<sub>&status=in_progress` 並重建 ownership。對 frontend 完全透明。
**為什麼選 A4 不選 A2啟動時批次掃**A2 對 converter 是 hammerA4 是 lazyuser 行為觸發cost 對應實際需求。
**新增依賴**converter Phase 1 的 `GET /api/v1/jobs?user_id=&status=in_progress` endpointconverter Phase 1 已實作)。已要求 PM 補進 §7 dependency 表§1.6)。
### 3.2 議題 #3 — `GET /api/conversion/active` 端點
**修訂**:原本 TDD 已有 `GET /api/conversion/active`,這次只是把它的 response shape 補上 `expires_at` / `source_filename` / `target_chip`並文件化「lazy rebuild」行為議題 #2)。
**修訂位置**`api/api-conversion.md` §5
**已對齊 Design 需求**wireframe §3.3 / flow §5.1 進入 `/conversion``/active` 直接落 processing 的設計,能拿到所有需要顯示的欄位(檔名、目標 chip、過期時間
### 3.3 議題 #5 — Cancel 清理鏈
**修訂**`conversion.md` §4.3.2(新增完整章節)
新增內容:
1. 4 種 cancel 觸發情境C1 使用者取消 / C2 重新整理 / C3 網路斷 / C4 converter 拒絕)
2. cleanup 鏈:`xhr.abort()` → TCP RST → `gin Context.Done()` → goroutine `pw.Close()` → io.Pipe EOF → converter multer abort
3. Best-effort `POST /api/v1/jobs/{id}/cancel`:當 backend 已拿到 job_id 但 streaming 失敗時,主動對 converter 發 cancel 避免孤立 job
4. §9 retry 表新增 `cancel` rowbest-effort、不重試
**重要區分**:「使用者主動取消 UI」PM Non-Goals N2Phase 1+ 才做vs 「backend 內部 best-effort cancel cleanup」TDD 此次補)— 兩者不衝突,後者是韌性 infra。
### 3.4 議題 #6 — Upload XHR 進度語意
**修訂**`conversion.md` §4.3.1(新增完整章節)
設計選擇表(選項 A vs B明確採選項 A**backend 等 converter 201 才回 200不 early-return**。理由:
- 進度 100% 接近端到端真實狀態
- 實作簡單(同步等)
- 失敗處理路徑清楚(同步錯誤直接回)
- 1-3 秒 io.Pipe drain 延遲對 500MB 上傳可接受
Frontend UX 補償100% 後到 backend 回 200 之間,文案切「即將完成…」/「伺服器處理中…」(已在 flow-conversion.md §5.3 提到)。已要求 Design 在 wireframe §4.2 對齊文案表§2.1.4)。
### 3.5 議題 #7 — `expires_at` 來源
**修訂**`conversion.md` §2.6.2(新增)+ `api/api-conversion.md` §1 / §2 / §5response shape 補欄位)
決策:
- 優先從 converter response 直接讀converter Phase 1 是否提供 — 給 Backend Agent 確認)
- 若 converter 沒給backend 自行 `created_at + 7d` 推算
- **Frontend 永遠拿到 `expires_at`**,無論來源
**Job response shape 統一補欄位**v0.3
- `expires_at`:必有
- `source_filename`:必有(給 success card 顯示「yolov5s.onnx → yolov5s_kl720.nef」
- `target_chip`:必有(給 wireframe §6 / §7 顯示「→ KL720」
### 3.6 同步影響的小修訂
- `conversion.md` §3 endpoint 表加註「不對外暴露但內部使用的 converter endpoint」cancel + lazy rebuild
- `conversion.md` §9 retry 表新增 cancel / lazy rebuild 兩 row
- `api/api-conversion.md` §3 promote-to-models request body 對齊 Design 單欄位(議題 #4
---
## 4. 給 Orchestrator 的決策清單
> 三方修訂大部分各自進行,以下是需要 Orchestrator 協調或使用者裁決的事項。
### 4.1 [使用者裁決] API endpoint 路徑命名統一
**問題**PM PRD 用 `/api/converter/jobs/*`、Design wireframe / flow 用 `/api/converter/jobs/*`、Architect TDD 用 `/api/conversion/*`,三方不一致。
**選項**
- **選項 A**Architect 建議):統一用 `/api/conversion/*``promote-to-models``GET /download` 302
- 優點:對齊 visionA 內部模組名(`internal/conversion/`ADR-014 v1.1 download 安全升級已採;命名語意清楚
- 改動PM PRD §F6 / F7、Design wireframe / flow多處
- **選項 B**:統一用 `/api/converter/jobs/*`
- 優點:與 converter 真實 path`/api/v1/jobs/*`)名字相近、有「轉發」直覺
- 缺點:誤導使用者以為是 raw proxy其實 backend 有 ownership / 半自動邏輯download flow 已決議用 GET 302不能維持 `POST /download-token`
**Architect 強烈建議選 A**
**決策後**
- 選 A → PM 改 PRD §F6/F7、Design 改 wireframe / flow標記位置已在 §1.2 / §2.1.2 / §2.2.2 列出TDD 不動
- 選 B → Architect 改 TDD 全部(`internal/conversion/` package 名也要改)— 不建議
### 4.2 [PM 待補] 修訂建議清單(嚴重度)
| # | 嚴重度 | 修訂位置 | 內容 |
|---|--------|---------|------|
| P1 | 嚴重 | §F6 / §F7 | 對齊 endpoint 命名(見 §4.1|
| P2 | 中 | §F 段(新增 F0| 補「Active job pre-check」功能 |
| P3 | 中 | §F2 / §F3 | 補上傳進度 100% 後的文案語意說明 |
| P4 | 中 | §F6 | 補「加到模型庫」Dialog 含名稱欄位(對齊 Design|
| P5 | 中 | §6 + §7 | 補 D7重啟 lazy rebuild+ converter dependency 補 2 個內部用 endpoint |
| P6 | 小 | §8 KPI | 量測點改為 backend log job 完成時間 |
| P7 | 小 | §F2 | 確認 chip 數量4 個 vs 2 個),與 converter 對齊 |
### 4.3 [Design 待補] 修訂建議清單(嚴重度)
| # | 嚴重度 | 修訂位置 | 內容 |
|---|--------|---------|------|
| D1 | 嚴重 | wireframe §3.3 / §6.3 / §7.1 / §7.2、flow §3 / §5.5 / §8.2 | 對齊 endpoint 命名(見 §4.1|
| D2 | 中 | wireframe §6.1 | stage indicator 改用 converter `stage` 欄位onnx/bie/nef → 解析/量化/編譯)|
| D3 | 中 | wireframe §4.2、flow §5.3 | 補 100% 後等待文案表 + i18n key |
| D4 | 中 | flow §5.3 / §8.2 | 補「使用者取消」vs「backend 內部 cancel cleanup」的區分 |
| D5 | 小 | wireframe §10 | Wand2 icon 採用(不需改)|
### 4.4 [需與其他團隊確認]
- **Backend Agent**:確認 converter Phase 1 的 `GET /api/v1/jobs/{id}` response 是否含 `expires_at`,決定 backend 是直接透傳還是自行推算
- **DevOps**:確認 visionA stage → 192.168.0.130 converter 網路可達性ADR-014 合規清單仍未勾)+ MC service client 4 scope 已授權
- **Converter 團隊**:確認 Phase 1 `platform` 欄位實際支援哪幾個 chip enum`520 / 720``520 / 630 / 720 / 730`
---
## 5. 結論
**已落地Architect 端)**4 個議題(#2 / #5 / #6 / #7)已寫進 `conversion.md` v0.3 + `api/api-conversion.md` v0.3。
**待 Orchestrator 協調**
1. 1 個使用者裁決API endpoint 命名統一§4.1
2. 7 個 PM 修訂1 嚴重 + 4 中 + 2 小
3. 5 個 Design 修訂1 嚴重 + 3 中 + 1 小
4. 3 個跨團隊確認
**建議下一步**
1. Orchestrator 把 §4.1 提給使用者裁決(這是阻擋三方對齊的單一最大議題)
2. 使用者決定後PM / Design 同步修訂(兩邊都在改 endpoint可平行進行
3. PM / Design 第二輪產出後Architect 再做最終 review確認沒新衝突
4. 完成後進 Phase 0.8 實作階段
---
## 版本記錄
| 日期 | 版本 | 變更 |
|------|------|------|
| 2026-04-30 | 1.0 | 初版 — Phase 0.8 三方交叉審閱Architect 視角)|