From 46514d77d70b9f1b0b852693eed6b2cf56ee2937 Mon Sep 17 00:00:00 2001 From: jim800121chen Date: Mon, 25 May 2026 07:40:56 +0800 Subject: [PATCH] =?UTF-8?q?docs(local-tool):=20M9=20=E2=80=94=20Kneron=20D?= =?UTF-8?q?ongle=20FW=20=E5=81=B5=E6=B8=AC=20+=20=E5=8D=87=E9=99=8D?= =?UTF-8?q?=E7=89=88=EF=BC=88A+B=E3=80=81=E7=BF=BB=E6=A1=88=20R5-Q9?= =?UTF-8?q?=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit L 級新功能、PRD/Design/TDD/ADR 三方協作 + 互審 + M9-6 SDK 雙驗證、總計 ~9000 行文件。 範圍: - A 階段(MVP、5 人天):KL520 + KL720 自動升級 KDP1 → KDP2 - B 階段(10.5 人天):手動降版面向一般使用者 + KL630 / KL730 擴展 - 合計 15.5 人天、安裝包 +7MB(保守 bundle 策略) 關鍵決策: - 翻案 R5-Q9(progress.md 第二輪使用者決策「韌體燒錄 flash → B 砍掉」) - 跨平台用 KneronPLUS Python C API、不用 DFUT.exe - 多版本目錄結構選 C metadata(firmware//{version}/ + CURRENT_VERSION) - Kneron firmware redistribution 授權與 R5-B4 預置模型同性質、發佈前評估 文件產出: - PRD v2.2(PRD-v2.md 495 行 + features/feature-firmware-management.md 599 行) - Design v2.2(firmware-management.md 948 行 + control-panel.md §6a graceful shutdown) - TDD v2.2(v2/firmware-management.md 823 行 + ADR-001 218 行) - 8 份 research(含 M9-6 弱驗證 + 強驗證、~3200 行) - 3 份三方互審報告(PM/Design/Architect cross-review) M9-6 強驗證重大發現(影響 B 階段): - KL730 product_id 實際是 0x732(不是 0x0730) - KL630/KL730 firmware 是 embedded Linux rootfs(不是 .bin、不同代設計) - KneronPLUS Python 沒 update_kdp_firmware_from_files 公開 API、warrenchen 走 ctypes - 不影響 A 階段、B 階段 M9-8 需 spike 下一步:派 backend M9-1 起跑(bridge.py handle_firmware_upgrade) Co-Authored-By: Claude Opus 4.7 (1M context) --- local-tool/.autoflow/02-prd/PRD-v2.md | 88 +- .../features/feature-firmware-management.md | 599 +++++++++++ ...-review-of-tdd-and-design-v2.2-firmware.md | 200 ++++ .../.autoflow/03-design/design-spec-v2.md | 26 +- ...ign-review-of-prd-and-tdd-v2.2-firmware.md | 476 +++++++++ .../.autoflow/03-design/v2/control-panel.md | 191 +++- .../03-design/v2/firmware-management.md | 948 ++++++++++++++++++ .../.autoflow/04-architecture/TDD-v2.md | 67 +- .../adr/ADR-001-firmware-management.md | 218 ++++ .../00-research-summary.md | 239 +++++ .../10-warrenchen-impl-analysis.md | 259 +++++ .../20-our-current-state.md | 292 ++++++ .../30-integration-plan.md | 662 ++++++++++++ .../40-b-phase-kl630-kl730-extension.md | 703 +++++++++++++ .../41-tar-firmware-handling.md | 458 +++++++++ .../42-manual-downgrade-for-end-users.md | 551 ++++++++++ .../50-m9-6-sdk-validation.md | 730 ++++++++++++++ .../55-m9-6-weak-validation-result.md | 332 ++++++ .../56-m9-6-strong-validation-result.md | 425 ++++++++ ...-review-of-prd-and-design-v2.2-firmware.md | 576 +++++++++++ .../04-architecture/v2/firmware-management.md | 823 +++++++++++++++ local-tool/.autoflow/progress.md | 180 +++- 22 files changed, 8984 insertions(+), 59 deletions(-) create mode 100644 local-tool/.autoflow/02-prd/features/feature-firmware-management.md create mode 100644 local-tool/.autoflow/02-prd/reviews/pm-review-of-tdd-and-design-v2.2-firmware.md create mode 100644 local-tool/.autoflow/03-design/reviews/design-review-of-prd-and-tdd-v2.2-firmware.md create mode 100644 local-tool/.autoflow/03-design/v2/firmware-management.md create mode 100644 local-tool/.autoflow/04-architecture/adr/ADR-001-firmware-management.md create mode 100644 local-tool/.autoflow/04-architecture/research-kl520-fw-management/00-research-summary.md create mode 100644 local-tool/.autoflow/04-architecture/research-kl520-fw-management/10-warrenchen-impl-analysis.md create mode 100644 local-tool/.autoflow/04-architecture/research-kl520-fw-management/20-our-current-state.md create mode 100644 local-tool/.autoflow/04-architecture/research-kl520-fw-management/30-integration-plan.md create mode 100644 local-tool/.autoflow/04-architecture/research-kl520-fw-management/40-b-phase-kl630-kl730-extension.md create mode 100644 local-tool/.autoflow/04-architecture/research-kl520-fw-management/41-tar-firmware-handling.md create mode 100644 local-tool/.autoflow/04-architecture/research-kl520-fw-management/42-manual-downgrade-for-end-users.md create mode 100644 local-tool/.autoflow/04-architecture/research-kl520-fw-management/50-m9-6-sdk-validation.md create mode 100644 local-tool/.autoflow/04-architecture/research-kl520-fw-management/55-m9-6-weak-validation-result.md create mode 100644 local-tool/.autoflow/04-architecture/research-kl520-fw-management/56-m9-6-strong-validation-result.md create mode 100644 local-tool/.autoflow/04-architecture/reviews/architect-review-of-prd-and-design-v2.2-firmware.md create mode 100644 local-tool/.autoflow/04-architecture/v2/firmware-management.md diff --git a/local-tool/.autoflow/02-prd/PRD-v2.md b/local-tool/.autoflow/02-prd/PRD-v2.md index ad6b628..6c99256 100644 --- a/local-tool/.autoflow/02-prd/PRD-v2.md +++ b/local-tool/.autoflow/02-prd/PRD-v2.md @@ -1,10 +1,10 @@ # visionA-local — 產品需求文件(PRD v2) -> 版本:**v2.1(2026-04-14)** +> 版本:**v2.2(2026-05-24)** > 作者:PM Agent -> 任務等級:L 級(重構方向變更) -> 狀態:**v2.1 補丁:吸收 R5-D1/D2/D3 + R5-E + Design 交叉審閱 4 Major / 4 Minor** -> 前版:`PRD-v2.md` v2.0(2026-04-14)/ [`PRD.md`](./PRD.md) v1.2(2026-04-11) +> 任務等級:L 級(v2.2 = 新增 FW 管理 feature,翻案 R5-Q9) +> 狀態:**v2.2 補丁:新增 Kneron Dongle FW 偵測 + 升降版(A + B 一次做完,~15.5 人天,+7MB)。詳見 [`features/feature-firmware-management.md`](./features/feature-firmware-management.md)** +> 前版:v2.1(2026-04-14,R5-D + R5-E)/ v2.0(2026-04-14,R5 重構)/ [`PRD.md`](./PRD.md) v1.2(2026-04-11) --- @@ -38,6 +38,10 @@ v2.1 為 Design 交叉審閱發回的小版本修正(Major 1–3 + 4 個 Minor **行數目標**:v2.1 新增約 40 行、精簡約 20 行,總量仍 ≤ 500 行。 +### v2.2 補丁摘要(相對 v2.1) + +v2.2 為**新增 feature**(不是修訂)——加入「Kneron Dongle FW 偵測 + 升降版」(A + B 一次做完),翻案 R5-Q9(progress.md 第二輪使用者決策 Q9 條目「韌體燒錄 flash → B 砍掉」、2026-04-11 拍板)。完整 user stories / AC / 風險 / milestone 在 [`features/feature-firmware-management.md`](./features/feature-firmware-management.md);本檔僅補:§4.4 對照表 + 新增 §4.5 索引 + §10 新增一列 + §11 新增 11-8 + 變更紀錄 v2.2。新風險 R-FW-1 ~ R-FW-14 在 feature 子檔 §8 詳述(v2.2.1 補強)。安裝包 +7MB(保守 bundle 策略,dmg 163MB → ~170MB,仍在 §6.2 上限內)。Kneron firmware redistribution 授權與 R5-B4 預置模型授權合併處理(同性質智財授權)。 + **保留 vs 重寫對照表:** | 章節 | 子檔 | v2 處理 | @@ -178,8 +182,20 @@ visionA-local 是一個**本機服務 + 網頁控制台**架構的 Kneron AI 邊 | Settings > 語言 / 深色模式 | P1, P2 | 瀏覽器 Web UI | | Settings > 自動開瀏覽器 | P1, P2 | **Wails 控制台**(因為它控制的是 Wails 啟動行為)| | Server Offline Overlay | 全體 | 瀏覽器 Web UI | +| **FW badge + 升級 modal**(v2.2 新)| P1, P2 | 瀏覽器 Devices 頁 | +| **Settings → 韌體管理**(v2.2 新,B 階段)| P1, P2 | 瀏覽器 Settings | | ~~Mock 模式~~ | ~~P3~~ | ~~砍~~ | +### 4.5 Kneron Dongle FW 偵測 + 升降版(v2.2 新增 feature) + +**翻案 R5-Q9**(progress.md 表格條目「Q9 韌體燒錄 flash → B 砍掉」,2026-04-11 第二輪決策)。當時砍的是「使用者燒任意 model 到 device flash」這條使用者旅程;v2.2 範圍切割後只做「升降版到 Kneron 官方 bundle 版本」,避開原始 brick 擔憂。完整 user stories(US-FW-1 ~ US-FW-3)/ AC / 風險 / milestone 詳見 [`features/feature-firmware-management.md`](./features/feature-firmware-management.md)。 + +- **A 階段(MVP,5 人天)**:KL520 + KL720 自動升級 KDP1 → KDP2、+0KB 安裝包、Devices 頁 FW badge(綠/黃/紅/灰)+ 升級 modal(M9-1 ~ M9-5)。**KL630/KL730 A 階段只做 FW 偵測(無升降版按鈕)**(v2.2.1 吸收 M9-6 弱驗證) +- **B 階段(擴展,10.5 人天)**:手動「韌體版本切換」面向一般使用者(UI 文案中性「韌體管理」/「切換到此版本」、不用「降版」字眼;含多層 safety net、不藏 dev mode、二次確認字串「DOWNGRADE」防誤觸)+ KL630/KL730 升降版(M9-10、含 AC-FW-3.5 生效條件 a/b/c)、+7MB(M9-6 ~ M9-13;M9-6 SDK 弱驗證已完成、強驗證 M9-9/M9-10 啟動前實機) +- **stage 命名統一**(v2.2.1):preparing / loading / flashing / verifying / done / error(採 Design 命名為 source of truth、WebSocket event stage + i18n key 一致) +- **新風險 R-FW-1 ~ R-FW-14**(v2.2.1 補 R-FW-13 wheel 三平台版本不一致 P1 / R-FW-14 大小寫繞過 P2),詳見 feature 子檔 §8 +- **與 R5-B4 合併處理**:Kneron firmware redistribution 授權與既有預置模型 redistribution 同性質(智財授權),發佈前一起取得 Kneron 書面授權;使用者明示「先不管授權、發佈前再評估」(feature 子檔 §9 Q-FW-1) + --- ## 5. User Stories(重寫受影響的) @@ -437,58 +453,35 @@ Architect TDD v2 必須產出 `scripts/build-ffmpeg-macos.sh`(記錄 configure --- -## 10. 變更追蹤(和 v1.2 的完整差異清單) +## 10. 變更追蹤(高階差異,逐項見 git history) -| 區域 | v1.2 | v2.0 | R5 依據 | +v1.2 → v2.x 已折成下方 bullet(原 25 項大表移除以保 500 行上限): + +- **定位轉向**(R5-1):Wails 內嵌 Next.js → 本機服務 + 網頁控制台(Ollama 式) +- **砍 Mock / URL 推論 / yt-dlp 35MB**(R5-5a / 共識 2):US-1/2/5/6/9 全面重寫 +- **ffmpeg GPL → LGPL 方案 B**(R5-6 系列):Win/Linux BtbN + macOS 自 build ~20MB +- **每次啟動自動開瀏覽器**(R5-4/D2/D3)+ AC-1.3 ≤60s perceived performance(R5-E1~E6) +- **新基礎建設**(R5-5/共識 5/6/8/14):Wails 控制台 + Offline Overlay 硬阻斷 + CORS + boot-id + watchServer Error state + Footer 警示 + Error 三按鈕 + 崩潰 OS 通知 +- **First-Run 3 步→2 步**(R5-5a / Minor 4);影片副檔名改 mp4/avi/mov/mpeg/mpg;macOS ≤ 185MB(v2.2 含 +7MB FW ~170MB);idle RAM ≤ 450/550MB + +**節錄表(僅 v2.2 新項與 v2.x 風險)**: + +| 區域 | v1.2 | v2.x | R5 依據 | |------|------|------|---------| -| 產品定位 | Wails 桌面 app 內嵌 Next.js UI | 本機服務 + 網頁控制台 | R5-1 | -| 競品類比 | Photo Booth | Ollama / Docker Desktop / LM Studio / SD WebUI | R5-1 | -| 一句話價值主張 | 「裝起來就能跑、離線可用、零依賴」 | 「雙擊 → 自動開瀏覽器 → 插 USB → 5 分鐘跑第一次推論」 | R5-1 / R5-4 | -| 北極星指標終點 | Mock 第一幀 | 瀏覽器第一幀(真實硬體)| R5-5a | -| Mock 模式 | MVP 必達 | **砍** | R5-5a | -| URL 影片推論 | US-8 / `/api/media/url` / yt-dlp 內嵌 | **砍** | R5 共識 2 | -| yt-dlp vendor(35MB)| 打包 | **砍** | R5 共識 2 | -| ffmpeg | GPL build(blocker 🔴)| **LGPL 方案 B 混合**(Win/Linux BtbN、macOS 自 build decoder-only ~20MB commit)| R5-6 / R5-6a / R5-6b / R5-6c | -| 安裝檔大小(macOS 目標)| ≤ 220 MB | **≤ 185 MB** | R5-6 | -| idle RAM(無硬體)| ≤ 500 MB / 上限 600 MB | ≤ 450 MB / 上限 550 MB | 砍 Mock / yt-dlp | -| Wails 視窗關閉 | 結束程式 | **同 v1.2**(R5-2 復議後維持)| R5-2 | -| Tray | 砍(v1.2 Q-A)| **同 v1.2**(R5-3 復議後維持)| R5-3 | -| 啟動時自動開瀏覽器 | 無 | **新增,每次啟動都開**(R5-D3),macOS/Win 預設 ON、**Linux 預設 OFF**(R5-D2),toggle 住 Wails 控制台 Settings(已與 Design 取得共識) | R5-4 / R5-D2 / R5-D3 | -| AC-1.3 啟動預算 | — | **≤ 60 秒**(原 v2.0 草案 10 秒硬指標被 R5-E1 取代)+ 階段化進度(6 階段,R5-E2)+ 20 秒卡住提示(R5-E3)+ 60 秒超時進 Error state(R5-E4)+ WebSocket 就緒偵測(R5-E6) | **R5-E1~E6** | -| Server 崩潰 OS 通知 | 無 | **新增**(控制台 Error banner 並存,R5-D1)| R5-D1 | -| First-Run wizard 步數 | 3 步(歡迎 / 模式選擇 / 硬體偵測) | **2 步**(歡迎 / 硬體偵測,砍模式選擇;無硬體可按「稍後再設定」略過) | R5-5a / Design review Minor 4 | -| Offline Overlay 硬阻斷 | — | **新增驗收特性**(`role="alertdialog"` + focus trap + 無 ✕ 按鈕 + 純色卡片) | Design review Minor 2 | -| Wails 控制台 Footer 持久警示 | 無 | **新增**「⚠ 關閉此視窗會停止 Local Server」取代單次 confirm 作為主要提醒 | Design review Minor 3 | -| Error state 三動作按鈕 | 無 | **新增** `Restart Server` / `View log` / `Report issue`(Wails 控制台 Error banner 內) | Design review Minor 3 | -| Wails 控制台 | 無(webview 載 Next.js)| **新增 vanilla HTML/JS/CSS**:Start/Stop/Restart/Open Browser/log panel/status/port/dir/version | R5-5 / R5 共識 5 | -| Server Offline Overlay | 無 | **新增**(Web UI 全螢幕覆蓋層)| R5-2 | -| CORS middleware | 無 | **新增**(127.0.0.1 / localhost only)| R5 共識 6 | -| watchServer 連 3 次失敗 | `os.Exit(1)` | **改為 Error state,不退出** | R5 共識 8 | -| Server boot-id | 無 | **新增**(支援 Restart Server 按鈕的 tab 自動重連)| R5 共識 14 | -| US-1 | 3 分鐘看到 Dashboard | 5 分鐘瀏覽器跑第一次推論 | R5-1 / R5-4 | -| US-2 | Mock 試玩 | 日常啟動(取代)| R5-5a | -| US-5 | Wails webview 攝影機 | 瀏覽器 Workspace + 後端攝影機 pipeline(不走 `getUserMedia`)| R5-1 | -| US-7 / US-8 | 影片 / URL 上傳 | 合併為 US-6,砍 URL | R5 共識 2 | -| US-9 | Settings 進階分頁次要功能 | **升級為 Wails 控制台一級功能** | R5-1 / R5-5 | -| 新 US-7(server 崩潰 / 離線)| 無 | **新增** | R5-2 | -| 上傳影片副檔名 | mp4 / avi / mov / webm(瀏覽器能吃)| **mp4 / avi / mov / mpeg / mpg** | R5 共識 11 | -| Persona P3 Sam | 三順位目標 | **實質降級為非目標** | R5-5a | -| 新風險 | — | N-R1 瀏覽器相容 / N-R2 macOS ffmpeg 維護 / N-R3 關窗誤解 / N-R4 CI 測試分層 | — | +| 新風險(v2.x)| — | N-R1 瀏覽器相容 / N-R2 macOS ffmpeg 維護 / N-R3 關窗誤解 / N-R4 CI 測試分層 + **R-FW-1 ~ R-FW-14(v2.2.1 補強 R-FW-13 wheel 三平台版本不一致 P1 / R-FW-14 大小寫繞過 P2)** | — / v2.2.1 | | 解除風險 | R6 ffmpeg GPL blocker | **解除** | R5-6 | +| **v2.2 新 feature** | — | **FW 偵測 + 升降版**(A+B、+7MB、~15.5 人天、翻案 R5-Q9;v2.2.1 吸收三方互審 + M9-6 弱驗證)| **§4.5 + feature 子檔** | --- ## 11. 給 Orchestrator / 下輪審閱的問題 -| # | 問題 | v2.1 狀態 | +| # | 問題 | 狀態 | |---|------|---------| -| 11-1 | auto-open Settings 資料落在哪?Web UI 和 Wails 控制台共用同一個 config 嗎? | ✅ **已解決**(Architect 答:`preferences.json @ /`,write-rename 原子寫,fallback DefaultPreferences;auto-open toggle 由 Wails 進程讀取,Web UI 不碰此欄位) | -| 11-2 | US-1 AC-1.3 10 秒預算是否可達? | ✅ **已解決(由 R5-E 取代)** — 整個問題被重新定義為「60 秒總預算 + 階段化進度 + perceived performance」,不再是硬時間指標 | -| 11-3 | idle RAM ≤ 450 MB 是否可達? | ✅ **已解決**(Architect 實測:Wails + Go server + Python 275–405 MB 達標;悲觀估含瀏覽器 tab ~500 MB 超 50 MB,但瀏覽器 tab 不在本指標範圍內,已於 §6.1 clarify) | +| 11-1 ~ 11-3 / 11-5 / 11-6 | v2.1 五題已解決(auto-open 落點、AC-1.3 預算、idle RAM、Web UI 徽章、Settings toggle 位置)| ✅ **已解決**(詳細結論散見 §1.4 / §6.1 / §4.5 N1-N2 / Design Spec v2 `v2/settings-update.md`;如需追溯,見 git log v2.1 提交)| | 11-4 | N-R4 砍 Mock 後 CI / E2E 測試分層 | ⏳ **懸置**,交 Testing Agent 在測試計畫提出「不需硬體的 UI 測試」vs「需硬體測試」分層方案 | -| 11-5 | Web UI 要不要加常駐「本機服務」徽章? | ✅ **已解決:不加**(Design Agent 決定,改由 First-Run Step 1 歡迎頁一次性告知;見 Design review §D) | -| 11-6 | Settings auto-open toggle 住哪裡? | ✅ **已解決**(Design 仲裁採 PRD 原案:住 Wails 控制台 Settings menu;Design Spec v2 `v2/settings-update.md` 將同步修正) | | 11-7 | R5-E 階段化進度 6 階段文案(中英雙語)定稿 | ⏳ **懸置**(R5-E5 使用者授權 Design Agent 決定;最終在 Design Spec v2 wireframe 定版時由使用者審閱 override) | +| 11-8 | FW 管理 feature 三方互審項 | ✅ **v2.2.1 已吸收**(D-FW-1~6 / A-FW-1~6 全部已處理、O-FW-1(與 R5-B4 release blocker 合併)+ O-FW-2(M9-10 AC-FW-3.5 條件評估)為 Orchestrator 追蹤項;詳見 [`features/feature-firmware-management.md`](./features/feature-firmware-management.md) §14)| --- @@ -496,5 +489,6 @@ Architect TDD v2 必須產出 `scripts/build-ffmpeg-macos.sh`(記錄 configure | 版本 | 日期 | 作者 | 變更 | |------|------|------|------| -| v2.0 | 2026-04-14 | PM Agent | 依 R5 五輪決策重寫:砍 Mock / URL 推論 / yt-dlp;新增 Wails 控制台 + Server Offline Overlay + 首次自動開瀏覽器 + CORS;ffmpeg 從 GPL blocker 解除為 LGPL 方案 B 混合;Persona P3 降級;US-1/US-2/US-5/US-6/US-7 重寫;解除 R6,新增 N-R1 ~ N-R4 風險。完整差異見 §10 | -| v2.1 | 2026-04-14 | PM Agent | 吸收 Design 交叉審閱(4 Major + 4 Minor)+ R5-D1/D2/D3 + R5-E1~E6:(1) 「首次啟動自動開」→「每次啟動自動開」全文修正(R5-D3);(2) auto-open 平台預設 Linux OFF(R5-D2);(3) US-7 新增 AC-7.7 Server 崩潰時發 OS 原生通知(R5-D1);(4) §4 新增 N7 OS 通知、N8 啟動階段化進度(6 階段);(5) **AC-1.3 從 10 秒硬指標改寫為 60 秒 + perceived performance + AC-1.3a/b/c/d 四條新驗收**(R5-E1~E6);(6) US-2 明確日常啟動同樣 auto-open(Minor 1);(7) Offline Overlay 補齊 `role="alertdialog"` + focus trap + 不可關閉 + 純色卡片(Minor 2);(8) US-7 AC-7.3 / AC-7.6 補 Wails 控制台 Footer 持久警示 + Error state 三動作按鈕(Minor 3);(9) US-1 AC-1.4 補 First-Run 從 3 步縮為 2 步 + 「稍後再設定」略過(Minor 4);(10) §6.1 idle RAM 加不含瀏覽器 tab 註記 + Architect 實測佐證;(11) §11 懸念 5 題結案 + 新增 11-6 / 11-7,保留 11-4 CI 測試分層懸置 | +| v2.0 / v2.1 | 2026-04-14 | PM Agent | R5 五輪決策重寫 + Design 互審吸收(詳見 §10 / git log) | +| v2.2 | 2026-05-24 | PM Agent | 翻案 R5-Q9、新增 FW 管理 feature(A+B、~15.5 人天、+7MB)。詳見 [`features/feature-firmware-management.md`](./features/feature-firmware-management.md) | +| v2.2.1 | 2026-05-25 | PM Agent | FW feature 吸收三方互審 + M9-6 弱驗證:①stage 命名採 Design(preparing/loading/flashing/verifying)②M9 工時表拆法採 PM(Architect 同意)③AC-FW-3.5(KL630/KL730 升降版)延後 B 階段 M9-10 + 生效條件 a/b/c、A 階段 KL630/KL730 只做 FW 偵測④ADR-009 → ADR-001 編號統一⑤R5-Q9 行號改描述式引用⑥US-FW-2 拆 2a / 2b + UI 文案中性化⑦補 §7.2.1 體驗指標 5 條⑧新增 R-FW-13/14⑨補 AC-FW-1.9 graceful shutdown⑩badge 4 色(補灰色)⑪11-8 解決。詳見 [`features/feature-firmware-management.md`](./features/feature-firmware-management.md) §14.4 | diff --git a/local-tool/.autoflow/02-prd/features/feature-firmware-management.md b/local-tool/.autoflow/02-prd/features/feature-firmware-management.md new file mode 100644 index 0000000..ae7751d --- /dev/null +++ b/local-tool/.autoflow/02-prd/features/feature-firmware-management.md @@ -0,0 +1,599 @@ +# feature: Kneron Dongle FW 偵測 + 升降版 + +> 對應 PRD:[`PRD-v2.md`](../PRD-v2.md) v2.2(2026-05-24) +> 作者:PM Agent +> 任務等級:L 級新功能(翻案 R5-Q9) +> 範圍:A 階段(MVP)+ B 階段(擴展),一次做完 +> 預估工時:A 5 人天 + B 10.5 人天 = **15.5 人天** +> 安裝包衝擊:+7MB(保守 bundle 策略,163MB → ~170MB) +> 狀態:**v2.2.1 — 吸收三方互審 + M9-6 弱驗證結果(裁決:stage 命名採 Design / M9 工時拆法採 PM / AC-FW-3.5 延後 B 階段 M9-10)** + +--- + +## 0. 一句話摘要 + +讓使用者把插上的 Kneron Dongle 從「Error 15 完全不能用的舊 FW」一鍵升級到內建 KDP2 標準版本,並提供面向一般使用者的多版本切換 UI(含降版),全程離線可用、不需要 DFUT.exe 或外部工具。 + +--- + +## 1. 動機 + +### 1.1 真實痛點:拿到舊 dongle 完全不能用 + +2026-04-21 的 bug 紀錄(progress.md §「2026-04-21 推論 bbox 標註不顯示 + KL520 Error 15」)已具體記錄: + +- KL520 USB Boot dongle 若 session 間 firmware 殘留 `fw=KDP2 Comp/U`,**直接 `load_model + inference` 100% 炸 `Error 15 SEND_DATA_TOO_LARGE`** +- 解法是強制走完整 `reset → 退回 Loader → 重新載 firmware` 流程 + +但這只解決「session 間殘留」,**沒解決「拿到一根插上是 KDP1 legacy 的舊 dongle」這個更基礎的問題**——使用者收到 Kneron 出貨的 dongle 可能是 KDP1(舊版)、可能是 KDP2 但版本太舊、可能 firmware 在運送過程被擦掉留在 Loader mode。所有這些情境的共通解法只有一條:**升級到 Kneron 官方 KDP2 標準版本**。 + +目前 visionA-local 沒有任何 UI 暴露「升級 firmware」這個動作,使用者只能: +1. 自己想辦法找 DFUT.exe(Windows-only Qt 工具) +2. 把 dongle 寄回 Kneron 換貨 +3. 放棄使用 + +→ 這違反 v1.2 北極星指標「**5 分鐘內順利跑出第一次推論的比例 ≥ 95%**」——只要使用者拿到不對版本的 dongle,5 分鐘永遠達不到。 + +### 1.2 為什麼現在做 + +| 觸發因素 | 說明 | +|---------|------| +| Architect 已完成 research plan | `.autoflow/04-architecture/research-kl520-fw-management/` 7 個檔、合計 ~3000 行,已驗證技術可行 | +| 同事 warrenchen 已有雲端版實作可參考 | `gitea/warrenchen/web_academy_prototype/local_service_win`,UX 旅程已被驗證 | +| KneronPLUS C API 跨平台可用 | `libkplus.{dll,so,dylib}` 三平台都在現有 bundle 內、增加成本 0KB | +| 使用者明確要求 + 願意翻案 R5-Q9 | 2026-05-24 拍板 A + B 一次做完 | +| 既有 code 已有 70% 邏輯 | bridge.py `handle_connect()` 已可偵測 Loader mode 並 RAM-load firmware,缺的只是「持久化升降版」 | + +--- + +## 2. R5-Q9 翻案分析 + +### 2.1 R5-Q9 原文(progress.md 第二輪決策表) + +``` +| Q9 | 韌體燒錄 flash | **B** 砍掉 | +``` + +**位置描述**:progress.md 「第二輪使用者決策」表格中、Q9 條目(2026-04-11 拍板)。行號因 progress.md 多次追加內容會浮動、文件追溯**以決策內容為準、不以行號為準**(早期 Architect research summary `00-research-summary.md` §1.7 與本檔早期版本均引用過 L776 / L854、僅供歷史追溯參考)。「Q9 韌體燒錄 flash 砍掉」的決策本身沒有疑義。 + +### 2.2 當時為何砍 + +progress.md 沒留下明文理由(只標「B 砍掉」)。Architect research 推測的 4 個可能原因(待使用者最終確認): + +1. visionA-local 定位是「local 推論工具」、不是「dongle 管理工具」,燒 flash 不屬核心使用旅程 +2. 燒 flash 有 brick 風險、當時不想對使用者開放 +3. 早期 MVP 範圍縮小、把非必要功能延後 +4. 既有「load_firmware 到 RAM」邏輯已夠用基本推論(KL520 USB Boot 每次重 load、KL720 已預燒 KDP2) + +### 2.3 現在為何要翻 + +| 因素 | 說明 | +|------|------| +| 真實痛點 | 2026-04-21 Error 15 經驗證實「舊 firmware = 完全不能用」 | +| 使用者明確要求 | 2026-05-24 拍板 A + B 全做 | +| 範圍可切割 | 只做「升級到內建 KDP2 標準版本」,不做「使用者燒任意 binary」 | +| Architect research 已驗證可行 | 5 人天 MVP、+0KB 安裝包、技術風險可控 | +| 同事雲端版已驗證 UX | warrenchen 雲端網頁 + 本地服務雙進程版已 ship,使用者旅程被驗證過 | + +### 2.4 範圍切割:避開 Q9 原始擔憂 + +| Q9 砍掉的 | 本任務不做 | 本任務做 | +|----------|-----------|---------| +| 「使用者按按鈕燒任意 model 到 device flash」 | ✅ 不做(與 model load 區隔) | — | +| 「開放使用者選任意 binary 寫 flash」 | ✅ 不做(只允許內建 bundle 過的官方 firmware) | — | +| — | — | ✅ 偵測 dongle 當前 FW 版本 | +| — | — | ✅ 升級到內建 Kneron 官方 KDP2 標準版本 | +| — | — | ✅ 切換到內建其他 bundle 版本(含降版) | + +→ **既有 `server/internal/flash/` 模組保持「load model 到 device RAM」原意**;新建 **`server/internal/firmware/`** 模組做升降版(Architect research §2.4 已明示模組劃分)。 + +### 2.5 決策痕跡 + +Architect 已於 [`ADR-001-firmware-management.md`](../../04-architecture/adr/ADR-001-firmware-management.md) 留下完整翻案理由與技術決策(Status: Accepted、2026-05-24)。本 feature 文件 + ADR-001 + progress.md 三處互相引用、確保未來回溯時不會誤會「為什麼第二輪砍了又補回來」。 + +--- + +## 3. 範圍切割:A / B 兩階段 + +### 3.1 A 階段(MVP):FW 偵測 + 自動升級 KDP1 → KDP2 + +**裝置範圍**:KL520 + KL720(既有 driver 已支援) + +**功能範圍**: +1. **被動偵測**:scan / connect 時讀取 firmware 字串、Devices 頁顯示 FW 健康度 badge(綠 = 最新、黃 = 可升、紅 = 必升) +2. **主動升級**(單一動作):使用者按「升級到最新」按鈕 → bridge.py 走 `kp.core.update_kdp_firmware_from_files` → progress 透過 WebSocket 推播 → 完成後自動 rescan +3. **不做手動降版 UI**(B 階段才做) + +**API 範圍**: +- `GET /api/devices/:id/firmware`(讀取 FW 狀態) +- `POST /api/devices/:id/firmware/upgrade`(觸發升級) +- WebSocket room `firmware:`(progress 推播) + +**安裝包衝擊**:+0KB(KL520/KL720 firmware 已 bundle 在 `server/scripts/firmware/`) + +**工時**:5 人天(M9-1 ~ M9-5,見 §10) + +### 3.2 B 階段(擴展):手動降版 + KL630/KL730 + +**裝置範圍擴展**:+ KL630 + KL730(需先擴 driver 處理 product_id 0x0630 / 0x0730 + .tar firmware) + +**功能範圍**: +1. **手動降版 UI(面向一般使用者)**:Settings → 「韌體管理」面板,不只 dev mode;含多層 safety net(見 §4) +2. **多版本 firmware 並存**:每個 chip 提供 current + 1-2 個降版選項 +3. **KL630/KL730 完整 FW 升降版**:含 .tar firmware 解壓邏輯(Architect M9-6 SDK 驗證待完成) +4. **KneronPLUS SDK 對 KL630/KL730 的 Python API 驗證**(M9-6) + +**API 範圍**: +- `GET /api/devices/:id/firmware/versions`(列出可選版本) +- `POST /api/devices/:id/firmware/downgrade`(觸發降版,需 `confirmToken: "DOWNGRADE"`) + +**安裝包衝擊**:+7MB(保守 bundle 策略;見 §6) + +**工時**:10.5 人天(M9-6 ~ M9-13,見 §10) + +### 3.3 A / B 範圍對照表 + +| 項目 | A 階段(MVP) | B 階段(擴展) | +|------|---------|---------------| +| **裝置範圍** | KL520 + KL720 | + KL630 + KL730 | +| **操作範圍** | 自動升級 KDP1 → KDP2 | + 手動降版 + 多版本選擇 | +| **使用者介面範圍** | Devices 頁 FW badge + 升級按鈕 + progress modal | + Settings → 韌體管理面板 + 二次確認 modal | +| **新增 API 數** | 3 個(GET firmware、POST upgrade、WS progress room) | + 2 個(GET versions、POST downgrade) | +| **bridge.py 新 handler** | `firmware_upgrade` | + `firmware_downgrade` + `firmware_list_versions` | +| **driver 新 method** | `UpgradeFirmware()` | + `DowngradeFirmware(version)` + `ListFirmwareVersions()` + `GetCurrentFirmwareVersion()` | +| **目錄結構** | 沿用 A 階段 `firmware//fw_*.bin` | 改 selecting C:`firmware//{v2.2.0,v2.1.0,kdp1}/` + `CURRENT_VERSION` | + +--- + +## 4. User Stories(面向「飛 firmware 痛點」的使用者旅程) + +### US-FW-1(A 階段 — 拿到舊 dongle 一鍵變可用) + +**身份**:P1 Arthur(內部 FAE)/ P2 Dora(外部開發者) + +**情境**:客戶現場、剛拿到 Kneron dongle(可能是 KDP1 legacy / 舊 KDP2),插上 USB + +**敘述**: +> 身為 FAE,我希望插上 dongle 後 Devices 頁立刻告訴我「這根 firmware 太舊、按下『升級到最新』就能用」,按下後 30 秒~3 分鐘內升級完成、自動 rescan、就能繼續正常 demo。 + +**驗收標準**: +- **AC-FW-1.1**:scan 後 Devices 頁卡片右上角顯示 FW badge:綠/黃/紅/灰 四色(綠 = 與內建 bundle current 相同;黃 = 比 current 舊但可升、含 v2.1.0 等 older 版本;紅 = legacy KDP1 系列或損毀 firmware 字串讀不到、必須升才能用;**灰 = 狀態未知**:壞掉 firmware / loader mode / KL630/KL730 A 階段「升降版尚未支援」狀態。Design v2.2 §4.2 標 3 色 + 補灰色 = 4 種總狀態)。Driver 層判定來源:`firmwareIsLegacy` / `firmwareCanUpgrade` / `bundledFirmwareVersion`(Architect TDD §3.1 衍生欄位) +- **AC-FW-1.2**:黃 / 紅 badge 點擊或卡片內「升級到最新」按鈕,跳出 progress modal,全程顯示**階段(採 Design 命名):preparing(準備中 / Preparing)/ loading(載入引導程式 / Loading loader)/ flashing(寫入韌體 / Flashing firmware)/ verifying(驗證中 / Verifying)/ done(完成 / Done)**+ progress bar + 不可中斷警告。WebSocket event 的 `stage` enum 值與 i18n key 與此命名一致(Architect TDD §4.3 stage 列舉同步、為 source of truth) +- **AC-FW-1.3**:升級成功後 modal 顯示 ✅ + 「裝置已升級到 v2.2.0」 + 自動關閉 modal(5 秒後)+ 觸發 Devices 頁 rescan + 卡片 badge 變綠 +- **AC-FW-1.4**:升級失敗時 modal 顯示明確失敗類型(Design v2.2 §7.1 列 8 種:scan / connect / loader / upgrade / verify / timeout / disconnect / 部分成功)+「複製錯誤訊息」按鈕 + 「重新插拔裝置後重試」指引;後端透過 `FirmwareProgress.reason` 細分 stage(Architect TDD §3.4 對應表) +- **AC-FW-1.5**:升級期間 device 進入 `StatusUpgrading` 狀態(既有 driver Status enum 擴展),鎖住其他操作(推論 / 切模型 / disconnect) +- **AC-FW-1.6**:升級成功後 device 會 re-enumerate(USB 拔插效果),bridge.py 必須等 **5-8 秒(實測 5 秒已穩、保留上界容忍)** 讓 USB stable 才主動 rescan(避免 KL520 reset bug 同樣坑,progress.md「2026-04-21 推論 bbox」紀錄已驗證機制) +- **AC-FW-1.7**:KL520 升級預估 ~30 秒(實測值)/ KL720 預估 ~180 秒(實測值);progress modal 顯示預估時間讓使用者不焦慮。**timeout 護欄上界**:KL520 ≤ 60s / KL720 ≤ 200s(§7.2 護欄、超過視為失敗) +- **AC-FW-1.8**:升級流程屬「device 層」失敗、不應觸發 `watchServer` Error state(與 Architect TDD v2.2 §8.1 解耦,research §2.1) +- **AC-FW-1.9(吸收 A-MID-1 + Architect §2.5)**:升級 / 降版進行中、Wails 控制台關閉視窗動作必須被擋下(防止 SIGTERM 中斷 firmware task brick 裝置),UI 顯示 modal「韌體切換進行中(device X)、為避免裝置損毀、無法關閉應用程式」、modal 不可 dismiss、等 firmware task 完成才能關 app(Architect TDD §8.6「graceful shutdown 拒絕」實作 + Design control-panel.md 補對應 modal) + +### US-FW-2a(B 階段 — 一般使用者主動切版本,相容性 / 回上版情境) + +**身份**:P1 / P2 — 一般使用者(FAE / 外部開發者,非純末端 consumer) + +**情境**(中、低頻率): +- 使用者升版後發現「我的舊 model 在新 FW 上跑不出結果」想回到 v2.1.0 +- 使用者跟某個 third-party tool 不相容、要回 KDP1 +- 使用者誤觸升級、想 revert +- 客戶現場 demo 需求特定版本 + +**敘述**: +> 身為一般使用者,我希望能去 Settings → 「韌體管理」面板,看到我每根 dongle 當前 FW 版本、bundle 內所有可選版本、每個版本的說明,能選一個並按下「切換到此版本」。我不希望點錯按鈕就 brick 裝置——應該要有明確警告 + 二次確認字串。 + +### US-FW-2b(B 階段 — 進階使用者跨版本切換,測試 / 開發情境) + +**身份**:P2 — 進階使用者 / 開發者 + +**情境**: +- 開發者測試多版本相容性 +- 測試環境需要特定版本 +- 「就是想試試看」 + +**敘述**: +> 身為開發者,我希望同一個「韌體管理」面板讓我自由在 bundled 版本間切換、UI 不對升 / 降特別 framing,方便我快速測試各版本行為。我能接受多一層確認流程作為 brick 防誤觸。 + +**framing 共識(Design + PM 對齊,吸收互審 MJ-D1)**: +- **UI 文案統一中性**:分頁名稱「韌體管理」、按鈕文案「切換到此版本」、warning 強調「切換可能影響相容性 / 不可中斷」、**不用「降版」字眼**(避免「面向一般使用者過於負面」+ 同時涵蓋 US-FW-2b 開發者跨版本切換情境) +- **程式碼 / log / API 內部用語可保留 `downgrade`**:API endpoint 仍是 `POST .../firmware/downgrade`、ADR / TDD / log 行為事件名稱保留技術詞(與 PRD §9 Q-FW-3 對齊 Design v2.2 §2.1 立場) +- **「DOWNGRADE」確認字串保留英文字面**:是 API contract、不 i18n 化(Architect 互審結論一致) + +### US-FW-2 共通驗收標準(US-FW-2a + US-FW-2b 適用) + +- **AC-FW-2.1**:入口在 Settings → 「韌體管理」面板(**不在 Devices 頁主流程**,避免誤觸;Architect research 42 §1.2 推薦;分頁順序「一般 / 硬體 / 韌體 / 模型 / 進階」見 Design v2.2 §2) +- **AC-FW-2.2**:列出所有偵測到的 dongle、每張一張卡片,顯示:dongle 名稱、kn_number、當前 FW 版本、bundle current 版本 +- **AC-FW-2.3**:卡片內「切換 FW 版本」accordion 展開後顯示版本 **radio list 或同等選擇 UI**(不限 dropdown — Design v2.2 §3.3 採 radio list,理由:版本 < 3 個、a11y 友善),每個版本顯示 displayName(如「v2.2.0 (current)」「v2.1.0 (older)」「KDP1 (legacy)」)+ 說明文案 + 預估時間 +- **AC-FW-2.4**:選了非當前版本後,「切換到此版本」按鈕變紅色(destructive 視覺、即使是切換到 newer 版本也統一處理),點擊後跳出二次確認 modal +- **AC-FW-2.5**:二次確認 modal 必含以下警告語(Design Agent 定稿文案): + - 「降版可能導致現有 model 無法運作」 + - 「降版過程不可中斷、否則裝置可能損壞」 + - 「降版完成後可能需要重新插拔裝置」 + - 「請確認版本相容性、降版至 KDP1 的舊版會限制可用功能」 +- **AC-FW-2.6**:二次確認 modal 強制使用者**輸入字面字串「DOWNGRADE」**才能點確認按鈕(防誤觸;input 欄空 / 不對時按鈕 disabled) +- **AC-FW-2.7**:二次確認 modal 不可被點外部關閉(必須點「取消」明確關閉),確認後 modal 不關閉、直接切「進行中」狀態(避免使用者誤以為什麼都沒發生) +- **AC-FW-2.8**:降版進行中、「進行中」UI **不顯示「取消」按鈕**(降版不可中斷),顯示 persistent banner「請勿拔除裝置」 +- **AC-FW-2.9**:API 層強制要求 request body 含 `confirmToken: "DOWNGRADE"`(字面字串);沒帶 / 帶錯 → 400(防 CSRF + 強制 UI 二次確認流程) +- **AC-FW-2.10**:Driver 層 safety guards: + - 拒絕跨晶片誤匹配(version 必須在 `ListFirmwareVersions(chip)` 結果內) + - 拒絕升版偽裝(目標版本 >= current → 拒絕、改走 upgrade API) + - 拒絕 no-op(目標版本 == current → 拒絕) + - 拒絕 status busy(device 在 `StatusInferencing` / `StatusFlashing` / `StatusUpgrading` 不接受降版) + +### US-FW-3(B 階段 — KL630/KL730 dongle 偵測 + 升降版) + +**身份**:P1 / P2 + +**情境**:客戶用 KL630 或 KL730(新一代 chip),插上後希望也能偵測 + 升降版 + +**敘述**: +> 身為使用者,我希望 KL630/KL730 跟 KL520/KL720 一樣支援 FW 偵測 + 升降版,UI 流程一致。 + +**驗收標準**: +- **AC-FW-3.1**:KL630/KL730 dongle 在 Devices 頁能被偵測(既有 driver `handle_connect()` 必須先擴展處理 product_id 0x0630/0x0730,progress.md 已標註) +- **AC-FW-3.2**:KL630/KL730 的 FW 升降版 UI 流程與 KL520/KL720 完全一致(複用同一套元件) +- **AC-FW-3.3**:bridge.py 必須能處理 .tar firmware(Architect M9-6 弱驗證確認「策略 Z 直接餵 .tar 給 SDK 不可行」、唯一可行解為 **策略 Y:build-time 解壓 .tar 找 .bin**;詳見 §8.3 + research 41 §4.4) +- **AC-FW-3.4**:升降版預估時間:KL630/KL730 ~60 秒(待 M9-10 強驗證實測校正) + +#### AC-FW-3.5(KL630/KL730 升降版 — **延後到 B 階段 M9-10 才實作**) + +**A 階段對 KL630/KL730**:**只做 FW 偵測**(顯示版本字串、Devices 頁 badge 可顯示「未知 / 待 M9-10」灰色 state),**不開放升降版動作**(無升級按鈕、無「切換 FW 版本」accordion)。 + +**B 階段 M9-10 才實作升降版**,理由(吸收 Architect M9-6 弱驗證結論,詳見 `research-kl520-fw-management/55-m9-6-weak-validation-result.md`): + +1. **無 warrenchen reference 實作**:warrenchen 對 KL630/KL730 完全沒寫 `/firmware/legacy-upgrade/kl630|730` endpoint、bridge.py 對 KL630/KL730 升降版要自己根據 KneronPLUS SDK 推(design risk 高) +2. **KneronPLUS wheel 三平台版本不一致**:macOS/Linux 是 2.0.0、Windows 是 3.1.2、A 階段要開 KL630/KL730 升降版必先處理三平台 wheel 統一(額外 1-1.5 人天 + KL520/KL720 regression 風險) +3. **無實機 verify 路徑**:A 階段不適合冒進、B 階段 M9-10 啟動時 KL630/KL730 實機已就位再驗 `update_kdp_firmware_from_files` 對 KL630/KL730 是否走同一條 flash 寫入路徑 + +**生效條件**(Architect 互審補充、M9-10 啟動前評估):以下任一條件成立 → M9-10 KL630/KL730 升降版可進入;任一條件不滿足 → 維持「只做 FW 偵測 / 不開升降版」: + +- **條件 a**:KneronPLUS Python wheel 對 product_id 0x0630/0x0730 有 `kp.core.update_kdp_firmware_from_files` 的 dispatch(或 ctypes-level `lib.kp_update_kdp_firmware_from_files` 對 KL630/KL730 確認可用) +- **條件 b**:策略 Y(build-time 解壓 .tar → 取得 `extracted/fw_scpu.bin` / `fw_ncpu.bin`)可正常 produce 兩個 .bin 路徑、且 SDK 接受餵這兩個 .bin(M9-8 已驗) +- **條件 c**:升級驗證階段、firmware 字串可穩定回讀(與 KL520/KL720 相同機制) + +任一條件不成立 → KL630/KL730 維持「只做 FW 偵測 only」、UI 顯示版本字串但無升降版動作 + 卡片標「升降版即將支援、目前僅顯示版本資訊」提示。最終決定回 Orchestrator 派 PM 微調 PRD(見 §14.3 O-FW-2)。 + +--- + +## 5. 手動降版面向一般使用者:user research 假設 + +### 5.1 為什麼不藏 dev mode + +使用者在 2026-05-24 明確決定「手動降版面向一般使用者」、不只 dev mode。理由(PM 推測 + 與使用者對話確認): + +| 假設 | 支持證據 | +|------|---------| +| H1:一般使用者也會遇到「model 在新 FW 上跑不出結果」 | progress.md L93 Error 15 經驗已暗示 firmware 版本對推論結果有影響 | +| H2:visionA-local 的目標使用者(P1 FAE、P2 開發者)技術水平夠高,能讀懂警告 | R5 Persona 定義 P1 是 FAE、P2 是「外部開發者」,都不是純末端 consumer | +| H3:藏在 dev mode 反而會讓真正需要降版的人找不到 | 內部 FAE 找不到 = 客戶現場 demo 失敗 | +| H4:safety net(二次確認 + 字面字串 + 警告語)足以擋住 90% 誤觸 | Architect research 42 §6 風險矩陣評估後殘餘風險低 | + +### 5.2 user research 待驗證項 + +| # | 項目 | 驗證方式 | 階段 | +|---|------|---------|------| +| UR-1 | 一般使用者是否會誤把「切換 FW 版本」當無害操作 | Beta 測試或 5 人 usability test | B 階段開發完成後 | +| UR-2 | 二次確認字串「DOWNGRADE」是否足以擋誤觸 | 同上 | B 階段開發完成後 | +| UR-3 | 「降版」這個詞是否會嚇跑使用者 | A/B 測試「切換 FW 版本」vs「降版」文案 | B 階段開發完成後 | +| UR-4 | brick 事件發生率(殘餘風險實測) | 上線後 6 個月追蹤客服回報 | Post-launch | + +→ B 階段上線時、UR-1/UR-2/UR-3 視機會做小規模測試;UR-4 是長期追蹤項。 + +### 5.3 情境分析 + +Architect research 42 §1.1 列出 5 個一般使用者會降版的情境(中、低頻率): + +| 情境 | 頻率 | 處理 | +|------|------|------| +| 「我的舊 model 在新 FW 上跑不出結果」 | 中 | 提供降版回 v2.1 選項 | +| 「跟某個 third-party tool 不相容」 | 低 | 提供降版回 KDP1 選項(僅 KL520) | +| 「我升錯了、想回到原本狀態」 | 低 | 提供「降版回上次版本」選項 | +| 「測試環境需要特定版本」 | 中 | 提供降版到任意 bundled 版本 | +| 「就是想試試看」 | 中 | 用警告語勸阻、但不阻止 | + +--- + +## 6. Bundle 策略與安裝包衝擊 + +### 6.1 使用者拍板的保守策略 + +| Chip | current | 額外 bundled | 合計(每 chip)| +|------|---------|------------|--------------| +| KL520 | v2.2.0 (~100KB) | v2.1.0 (~100KB) + kdp1 (~90KB) | ~290KB | +| KL720 | v2.2.0 (~250KB) | v2.1.0 (~250KB) | ~500KB | +| KL630 | SDK-v2.5.7 (~3MB) | + extracted (~3MB) | ~6MB | +| KL730 | SDK-v1.3.0 (~4MB) | + extracted (~4MB) | ~8MB | +| **合計** | | | **~15MB**(保守估計),實際 ~7MB(因 KL630/KL730 解壓策略未定,可能不需 extracted) | + +### 6.2 多版本目錄結構(選項 C) + +使用者拍板選 C — `firmware//{v2.2.0,v2.1.0,kdp1}/` + `CURRENT_VERSION` 單行檔(Architect research 42 §3.2 / §3.3)。 + +理由: +- 跨平台無 symlink 風險(vs 選項 A symlink) +- 節省空間(vs 選項 B 實體副本) +- 架構乾淨清晰 + +### 6.3 安裝包大小衝擊 + +- 既有 dmg:163MB +- A 階段:+0KB → 163MB +- B 階段(保守):+7MB → **~170MB** + +→ 在 PRD v2.1 §6.2 「macOS dmg 目標 ≤ 185MB / 上限 ≤ 220MB」範圍內,無需 PRD §6.2 數字調整。 + +**使用者體驗層面**(吸收 Design P-LOW-2):+7MB 對下載 / 安裝時間影響:寬頻 ~50MB/s → +0.14 秒(無感)/ 一般 4G hotspot ~5MB/s → +1.4 秒(無感)/ 慢速 wifi ~1MB/s → +7 秒(有感但可接受、屬罕見場景) + +### 6.4 不做線上更新通道 + +使用者拍板「不做線上更新通道、所有 firmware 內嵌」(progress.md 2026-05-24)。 + +→ 不實作 OTA / 不做 firmware 從遠端 fetch。所有可用版本就是 bundle 內的版本。 + +→ 風險:未來 Kneron 出新 firmware 版本時必須打新安裝包才能用(接受此 trade-off,因為使用者明確要 offline-first)。 + +--- + +## 7. 成功指標 + +### 7.1 主要指標(與 PRD v2.1 §1.4 北極星指標掛鉤) + +| 指標 | baseline | A 階段目標 | B 階段目標 | +|------|---------|-----------|----------| +| **5 分鐘首次推論達成率**(PRD v2.1 北極星)| 假設受 firmware 問題影響 ~10% | **+ 5pp**(從「拿到舊 dongle 完全不能用」變「+ 30 秒升級即可用」) | 維持 | +| **拿到舊 dongle 後完成首次推論的中位時間** | 不可估算(需重新出貨)| **≤ 5 分鐘**(自動升級流程內) | 維持 | + +### 7.2 次要指標 + +| 指標 | 目標 | source | +|------|------|--------| +| FW 升級成功率(A 階段,KL520 + KL720)| ≥ 95% | log 統計(非自動 telemetry、技術支援彙整)| +| FW 降版成功率(B 階段,KL520 + KL720)| ≥ 95% | 同上 | +| FW 升降版平均時長(護欄)| KL520 ≤ 60s / KL720 ≤ 200s / KL630/KL730 待 M9-10 強驗證校正 | log 統計 | +| 一般使用者誤觸降版發生率(B 階段上線後 3 個月)| ≤ 1% | 客服回報統計 | +| Brick 事件(B 階段上線後 6 個月) | ≤ 0.1%(< 1 / 1000 dongles) | 客服回報 | + +**注意(吸收 Architect §1.2)**:v2.2 階段大部分 FW 指標**靠客服回報 + log 統計、非自動上報**;自動 telemetry 是未來 feature、不在本 PRD scope。 + +### 7.2.1 體驗指標(吸收 Design P-MID-1) + +「以下指標補強 §7.2 純技術指標、量測使用者體驗層面是否健康」: + +| 指標 | 目標 | source / 量測方式 | +|------|------|------| +| **升級任務完成率**(modal 開啟 → 升級成功 toast)| ≥ 85% | log 統計(modal-opened 事件 vs upgrade-success 事件配對)| +| **二次確認 modal 中途放棄率**(B 階段降版) | 50-70%(合理區間)| log 統計(confirm-modal-shown vs token-typed-and-confirmed 配對)| +| **Devices 頁 FW badge 點擊率**(只算紅 / 黃 badge)| ≥ 30% | 前端 click 事件統計 | +| **升級失敗後重試率**(首次失敗後 5 分鐘內重試比例)| 視底線、追蹤即可 | log 統計 | +| **B 階段 SUS 分數**(5 人 usability test)| ≥ 65 | Beta 階段 usability test、見 §5.2 UR-1~3 | + +**解讀準則**: +- 二次確認中途放棄率 < 50% 暗示「UX 不夠恐嚇」(應加強警告) +- 二次確認中途放棄率 > 70% 暗示「嚇跑使用者」(應減弱警告) +- FW badge 點擊率 < 30% 暗示「使用者沒注意到要升級」(應加強顯著性 / IA) + +### 7.3 護欄指標(不可惡化) + +| 指標 | 上限 | +|------|------| +| dmg 安裝包大小 | ≤ 220MB(PRD v2.1 §6.2 上限)| +| FW 升降版期間 server 是否進 Error state | 不可(device 層失敗、與 server 解耦)| +| FW 升降版期間其他 device 是否能正常推論 | 可以(device 之間互不影響)| +| 啟動時間 | ≤ 60 秒(PRD v2.1 AC-1.3,FW 升降版不在啟動 pipeline 內、無影響)| + +--- + +## 8. 風險與已知限制 + +承前 Architect research 30 + 40 + 41 + 42 的風險清單,PM 視角彙整為 **R-FW-1 ~ R-FW-12**(不重寫技術細節,引用 research)。 + +### 8.1 R-FW-1 ~ R-FW-7(A + B 階段共通,來自 Architect research 30) + +| ID | 風險 | 可能性 | 影響 | 等級 | 緩解 | 詳見 | +|----|------|-------|------|------|------|------| +| R-FW-1 | KL520 reset bug 再現(升級後 device re-enumerate 不穩定)| 中 | 中 | P2 | 升級後等 5-8 秒 + 主動 rescan,承襲 2026-04-21 修法 | research 30 §3 | +| R-FW-2 | KneronPLUS Python wheel 版本對 update API 支援度不足 | 低 | 高 | P1 | **M9-6 弱驗證已確認** 3.1.2 wheel 對 `update_kdp_firmware_from_files` 完整支援(warrenchen 使用中)、剩 macOS/Linux 2.0.0 wheel enum 待 35 分鐘強驗證;策略 Y(解壓 .tar 取 .bin)唯一可行解 | research 30 §4 + 40 §5 + **55-m9-6-weak-validation-result.md** | +| R-FW-3 | bridge.py `kp.core.update_kdp_firmware_from_files` 在 macOS x86_64 行為未驗證 | 低 | 中 | P2 | **M9-6 弱驗證**:API 簽名與 warrenchen 一致、預期 macOS/Linux 2.0.0 + Windows 3.1.2 KL520/KL720 升級可用;M9-1 開發前 backend agent 跑 35 分鐘強驗證、若 enum 不存在則升 wheel(牽動三平台 wheel 統一) | research 30 §4 + **55-m9-6-weak-validation-result.md** | +| R-FW-4 | 升級 timeout 設定不合理(太短 = 誤判失敗、太長 = 卡 UI)| 低 | 中 | P3 | 採 warrenchen 經驗值(KL520 30s / KL720 180s)+ progress 推播提供使用者感知 | research 30 §5 | +| R-FW-5 | 打包 Kneron 官方 firmware 是否合法(與 R5-B4 預置模型授權同性質)| 高 | 高 | **P0**(發佈 gate)| 使用者明示「先不管授權、發佈前再評估」、PRD 標註為未解決問題(§9)| research 00 §1.7 + 40 §7 + 42 §7 | +| R-FW-6 | 既有 `flash/` 模組名稱混淆(load model 到 RAM vs 燒 firmware)| 低 | 低 | P3 | 新建 `firmware/` 模組、保持 `flash/` 原意(Architect research §2.4)| research 00 §2.4 | +| R-FW-7 | 升級失敗 device 進入 unknown state(既不能用舊 firmware、新 firmware 也沒寫成功)| 低 | 高 | P1 | bridge.py 失敗時不切換 device.firmware 字串、UI 提示重新插拔;Plan B:技術支援 SOP 用 DFUT.exe 救磚(不打包進 app) | research 30 §6 + 42 §6.3 | + +### 8.2 R-FW-8 ~ R-FW-12(B 階段新增,來自 research 40 + 42) + +| ID | 風險 | 可能性 | 影響 | 等級 | 緩解 | 詳見 | +|----|------|-------|------|------|------|------| +| R-FW-8 | KneronPLUS SDK 對 KL630/KL730 API 行為不可預測 | 高 | 中 | P1 | M9-6 SDK 驗證(與 A 階段平行進行,progress.md 2026-05-24 拍板)| research 40 §5 | +| R-FW-9 | .tar 解包對安裝包大小衝擊(如果採策略 X build-time 解壓 + bundle)| 低 | 低 | P3 | 採策略 Y 或 Z 平衡空間 vs 速度(M9-6 結論定)| research 41 §3 | +| R-FW-10 | KL630/KL730 沒有 Loader mode 概念(與 KL520 USB Boot 流程不同)| 中 | 中 | P2 | bridge.py `handle_connect()` 必須 chip-aware 分流(既有 fall-through 到 KL520 是 bug、會連不上)| research 40 §3 | +| R-FW-11 | 一般使用者誤觸降版導致 brick | 高 | 高 | **P1** | 多層 safety net:UI 警告 + 二次確認字串 + driver guard + 進行中 banner(research 42 §5/§6 + 本檔 AC-FW-2.5 ~ 2.10)| research 42 §6 | +| R-FW-12 | 多版本管理 UX 複雜度(使用者看不懂 v2.2.0 vs v2.1.0 vs KDP1)| 中 | 中 | P2 | **已具體落地**:Design v2.2 §3.3 accordion + radio list + 每個版本 displayName 後綴(current/older/legacy)+ §9 i18n 涵蓋;KDP1 額外紅色警告 banner | research 42 §5.3 + Design v2.2 §3.3 / §9 | +| **R-FW-13** | **KneronPLUS wheel 三平台版本不一致**(macOS/Linux 2.0.0 vs Windows 3.1.2)| 高 | 中 | **P1** | **A 階段**:先在 macOS/Linux 強驗證 2.0.0 wheel 是否含 KL520/KL720 update API(M9-1 啟動前 35 分鐘)、預期可用、若不可用先升 Windows 對齊;**B 階段 M9-10 啟動前必須升 macOS/Linux 到 3.1.2**(含 KL630/KL730 enum)+ 跑 KL520/KL720 三平台 E2E 回歸(M9-13) | **55-m9-6-weak-validation-result.md** 發現 6 | +| **R-FW-14**(Frontend 防誤觸補強) | 使用者輸入「downgrade」小寫繞過確認 | 低 | 高 | P2 | Frontend 用嚴格 `===` 比對、**不用 `.toUpperCase()`**;後端 API 同時雙重比對;M9-12 Reviewer 必檢查 | Design v2.2 §12.2 R-FW-11.5 自提 + Architect §2.10 同意 | + +### 8.3 與既有架構的衝突已釐清項 + +| 衝突點 | 結論 | 詳見 | +|--------|------|------| +| **watchServer Error state**(TDD v2.1 §8)| FW 升降版失敗屬 device 層、與 server 層 watchServer 解耦、不觸發 Error state | research 30 §2.1 | +| **R5-E 60s 啟動上限** | FW 升降版是使用者主動觸發、不在啟動 pipeline 內、無關 | research 30 §2.3 | +| **KL520 reset bug fix**(2026-04-21)| 升級成功後 device re-enumerate 必須等 5-8 秒 + 主動 rescan、不立即 reconnect | research 30 §2.2 | +| **既有 `flash/` 模組命名包袱** | 不改檔名(本任務範圍外)、新文件命名用 `kneron_*` 或 `device_firmware_*` | research 30 §2.5 | + +--- + +## 9. 未解決問題(彙整給 Orchestrator) + +| # | 問題 | 性質 | 處理建議 | +|---|------|------|---------| +| Q-FW-1 | Kneron firmware redistribution 授權(含舊版 v2.1.0 / KDP1) | **發佈前 gate**(與 R5-B4 預置模型授權同性質)| 使用者明示「先不管授權、發佈前再評估」,PRD 留紀錄。建議發佈前 3-6 個月與 Kneron 取得明確書面授權,授權範圍含 current + 舊版(v2.1.0 / KDP1)+ KL630/KL730 firmware tar | +| Q-FW-2 | KneronPLUS Python wheel 對 KL630/KL730 update API 支援度 | **B 階段啟動 gate** | M9-6 SDK 驗證為先(與 A 階段平行)、結論定 B 階段 scope;若不支援、AC-FW-3.5 啟動「降級為 FW 偵測 only」 | +| Q-FW-3 | 「降版」這個詞是否用於 UI 文案 | **✅ 已決定(吸收三方互審 MJ-D1)** | UI 文案統一中性(分頁名稱「韌體管理」、按鈕「切換到此版本」),**不用「降版」字眼**;程式碼 / log / API 內部用語可保留 `downgrade`、API endpoint 仍是 `POST .../firmware/downgrade`。對齊 Design v2.2 §2.1 + Architect 同意 | +| Q-FW-8(新)| 「DOWNGRADE」確認字串是否 i18n 化 | **✅ 已決定(吸收 Design D-M3 + Architect §2.2)** | 保留英文字面 `"DOWNGRADE"`、是 API contract 不 i18n 化;UI 提示文字 i18n 化(如「請輸入 DOWNGRADE 確認」中文 + 「Type DOWNGRADE to confirm」英文),但 input 比對的字串跨語系一致 | +| Q-FW-4 | 一般使用者降版的 user research 假設驗證時機 | **B 階段 post-launch** | UR-1/UR-2/UR-3 在 Beta 階段做 5 人 usability test;UR-4 brick 事件追蹤 6 個月(§5.2)| +| Q-FW-5 | KL520 / KL720 / KL630 / KL730 升降版預估時間是否準確 | **開發階段實測** | M9-5(A)/ M9-13(B)三平台實機驗證時校正 | +| Q-FW-6 | progress.md R5-Q9 行號 L776 vs L854 不一致 | **✅ 已決定** | 文件追溯以「progress.md 第二輪使用者決策 Q9 條目」描述式引用為準、不引用行號(行號因 progress.md 多次追加會浮動)。決策本身明確:2026-04-11 第二輪 Q9 「韌體燒錄 flash → B 砍掉」、本 PRD §2.1 已修正 | +| Q-FW-7 | 升級失敗後的「救磚 SOP」是否需要在 UI 內提示 | **B 階段 Design 決定** | 目前傾向:UI 提示「請重新插拔裝置後重試」+「複製錯誤訊息」+ 技術支援聯絡資訊(research 42 §6.3 SOP 留內部 wiki)| + +--- + +## 10. 工時與 Milestone + +### 10.1 A 階段(M9-1 ~ M9-5、共 5 人天,PM 拆法、Architect 互審同意採此版本) + +| # | Milestone | 工時 | 依賴 | 平行性 | +|---|-----------|------|------|-------| +| M9-0 | 開發前強驗證(backend agent、35 分鐘):macOS/Linux 跑 `python3 -c "import kp; print(kp.ProductId.KP_DEVICE_KL630)"`、判斷 2.0.0 wheel 是否含 KL630/KL730 enum + `tar -tvf` inspect firmware .tar | < 0.1 人天(內含)| — | M9-1 之前必跑 | +| M9-1 | bridge.py 新增 `firmware_upgrade` handler(KneronPLUS C API、策略 Y 唯一可行解)| 1 人天 | M9-0 | 獨立 | +| M9-2 | Go driver + service:`UpgradeFirmware()` + `server/internal/firmware/service.go` + safety guards | 1 人天 | M9-1 | — | +| M9-3 | API handler + WebSocket progress room(含 `FirmwareProgress.reason` 細分 stage、Elapsed/ETA 欄位、graceful shutdown 拒絕邏輯 hook 點)| 0.5 人天 | M9-2 | — | +| M9-4 | 前端 Devices 頁 FW badge(4 色含灰色狀態未知)+ 升級按鈕 + progress modal + 6 個 component-level design tokens 落地(含 a11y 對比驗證)| 1.5 人天 | M9-3 | 與 M9-1/M9-2/M9-3 部分平行(mock API)| +| M9-5 | 三平台實機驗證(macOS / Windows / Linux × KL520 + KL720 完整升級 E2E)| 1 人天 | 全部前置完成 | — | +| **A 合計** | | **5 人天** | | | + +### 10.2 B 階段(M9-6 ~ M9-13、共 10.5 人天,PM 拆法、Architect 互審同意採此版本) + +| # | Milestone | 工時 | 依賴 | 平行性 | +|---|-----------|------|------|-------| +| M9-6 | KneronPLUS SDK 對 KL630/KL730 + .tar firmware Python API 驗證(**弱驗證已完成**:見 `55-m9-6-weak-validation-result.md`;強驗證須等 KL630/KL730 實機)| 1 人天(含弱驗證 0.5 + 強驗證 0.5)| — | **與 A 階段平行**(2026-05-24 使用者決策)| +| M9-7 | Driver 擴展處理 product_id 0x0630/0x0730 + chip-aware connect 分流(含 KL630/KL730 firmware 載入分支)| 1.5 人天 | M9-6 | — | +| M9-8 | bridge.py 處理 .tar firmware(**策略 Y 唯一可行解、build-time 解壓**;策略 Z 已被弱驗證排除)| 1.5 人天 | M9-7 | — | +| M9-9 | 多版本目錄結構重整(A 階段檔案搬到 `/v2.2.0/` + 加 `CURRENT_VERSION`)+ bridge.py 升級 `_resolve_firmware_paths_versioned()` | 1 人天 | A 階段完成 | — | +| M9-10 | **KL630/KL730 升級 / 降版 driver method 實作**(AC-FW-3.5 生效條件評估在此 milestone 啟動時跑、無 warrenchen reference 實作、design risk 較高)| 1.5 人天 | M9-8 + M9-9 + M9-6 強驗證完成 + macOS/Linux wheel 升 3.1.2(R-FW-13)| — | +| M9-11 | 多版本降版後端(API + bridge.py + driver guards + graceful shutdown 拒絕落地)| 1.5 人天 | M9-9 | — | +| M9-12 | 降版 UI(Settings 韌體管理面板 + 二次確認 modal + 進行中 UI + Wails 控制台關閉攔截 modal)| 2 人天(Frontend 1 + Design 1)| M9-11 | Design + Frontend 平行 | +| M9-13 | B 階段三平台實機驗證 + KL520+KL720 wheel 升級 regression + Beta usability test(UR-1/UR-2/UR-3)| 1 人天 | M9-7 ~ M9-12 全部 | — | +| **B 合計** | | **10.5 人天** | | | + +### 10.3 合計 + +- A + B = **15.5 人天** +- 與 Architect research 結論一致 + +--- + +## 11. 涉及檔案 / 模組(從 Architect research 30 + 40 摘要) + +### 11.1 新建模組 + +``` +server/internal/firmware/ ← 新模組(升降版核心) +├── service.go ← FirmwareService 提供 Upgrade/Downgrade/List +├── versions.go ← 版本管理 + 比較邏輯(isOlderVersion()) +└── safety.go ← driver guard helpers(不跨晶片 / 不升版偽裝 / 不 no-op) +``` + +### 11.2 既有檔案修改 + +| 檔案 | 修改範圍 | 階段 | +|------|---------|------| +| `server/scripts/kneron_bridge.py` | 新增 handler:`firmware_upgrade` / `firmware_downgrade` / `firmware_list_versions` | A + B | +| `server/internal/driver/kneron/kl720_driver.go` | 新增 method:`UpgradeFirmware` / `DowngradeFirmware` / `ListFirmwareVersions` / `GetCurrentFirmwareVersion` | A + B | +| `server/internal/driver/types.go` 或同等 | DeviceDriver interface 擴展 + `FirmwareVersion` / `FirmwareProgress` struct | A | +| `server/internal/api/handlers/device_handler.go` 或新檔 | 新 endpoint:`GET /api/devices/:id/firmware*` / `POST .../upgrade` / `POST .../downgrade` | A + B | +| `server/internal/api/router.go` | 註冊新路由 | A + B | +| `server/internal/ws/hub.go` | 註冊 `firmware:` WebSocket room | A | +| `server/scripts/firmware/` | 重整目錄結構為 `//` + `CURRENT_VERSION` | B(M9-9)| + +### 11.3 前端新增 / 修改 + +| 檔案 | 修改範圍 | 階段 | +|------|---------|------| +| `frontend/components/devices/device-card.tsx` 或同等 | 加 FW badge(綠/黃/紅)+ 升級按鈕 | A | +| `frontend/components/devices/firmware-upgrade-modal.tsx`(新) | progress modal | A | +| `frontend/pages/settings/firmware.tsx` 或同等(新) | Settings → 韌體管理面板 | B | +| `frontend/components/firmware/version-switch-modal.tsx`(新) | 二次確認 modal | B | +| `frontend/components/firmware/downgrade-progress-modal.tsx`(新) | 進行中 UI | B | +| i18n keys | +46 個(research 42 §5.6 估算) | B 為主 | + +### 11.4 文件新增 + +| 檔案 | 角色 | 階段 | +|------|------|------| +| `docs/autoflow/04-architecture/adr/ADR-001-firmware-management.md` 或同等 | Architect 留 R5-Q9 翻案紀錄 + 技術決策 | A 啟動前 | +| `docs/autoflow/04-architecture/TDD-v2.md` §5.4 firmware 子節 | Architect 補 TDD v2.2 | A 啟動前 | +| `docs/autoflow/03-design/design-spec-v2.md` 對應子節 | Design Agent 補設計規格 v2.2 | A 啟動前 | +| `docs/autoflow/02-prd/features/feature-firmware-management.md`(本檔)| PM 補 PRD v2.2 | 進行中 | +| `docs/troubleshooting/brick-recovery.md`(內部 wiki)| 技術支援 SOP(DFUT.exe 救磚流程,**不打包進 app**)| 上線前 | + +--- + +## 12. 與既有 R5 決策的關係 + +| R5 條目 | 本任務關係 | +|---------|----------| +| **R5-Q9(砍 flash)** | **翻案**(§2),透過範圍切割避開原始擔憂 | +| **R5-B4(Kneron 預置模型 redistribution)** | 同性質問題擴展 — 本任務的 firmware bundle 與 R5-B4 同樣是「打包 Kneron 智財」、發佈前須一起跟 Kneron 取得授權(§9 Q-FW-1)| +| **R5-E(60s 啟動 + perceived performance)** | 無關 — FW 升降版不在啟動 pipeline 內(research 30 §2.3)| +| **R5-D1(Server 崩潰 OS 通知)** | 不擴展 — FW 升降版失敗屬 device 層、不發 OS 通知(與 device toast 一致,PRD v2.1 §AC-3.7 + R4-8 策略)| +| **R5-1(產品定位)** | 對齊 — FW 管理 UI 住瀏覽器 Web UI(Devices 頁 + Settings 韌體管理)、不住 Wails 控制台 | +| **R5-3(砍 tray)** | 無衝突 | +| **R5-6(ffmpeg LGPL)** | 無關 | + +--- + +## 13. 風險:本 feature 對既有功能的影響 + +承前 R5「既有專案的每一步都需要特別小心、避免破壞現有功能」原則,本 feature 的潛在影響: + +| 影響範圍 | 風險 | 緩解 | +|---------|------|------| +| 既有 KL520 / KL720 推論流程 | 升級期間 device 鎖住 `StatusUpgrading`、其他操作會被擋 | 預期行為、UI 清楚告知 | +| 既有 `flash/service.go` (load model 到 RAM)| 命名 vs 新 `firmware/` 模組可能混淆 | 嚴格保持 `flash/` 原意、新模組獨立目錄(research §2.4)| +| KL630 / KL730 連線(既有 fall-through 到 KL520 bug)| 本任務 M9-7 必修,否則 KL630/KL730 連不上 | M9-7 是 B 階段必做、driver 改動需 Reviewer 把關 | +| 既有 `kneron_bridge.py handle_connect()` | 新增 handler 不影響既有 connect 流程(獨立 handler)| Architect 確認 | +| 安裝包大小(既有 dmg 163MB)| +7MB → ~170MB,仍在 PRD v2.1 §6.2 上限內(≤ 220MB)| 已在範圍內,無需 PRD §6.2 數字調整 | + +--- + +## 14. 三方互審回饋處理紀錄(v2.2 → v2.2.1) + +### 14.1 給 Design Agent — **全部已處理** + +- **D-FW-1**(降版入口位置):✅ Design v2.2 §2 採 Settings 第 3 分頁「韌體管理」、與 PM 對齊 +- **D-FW-2**(「降版」用詞):✅ **已決定**:UI 統一中性「韌體管理」/「切換到此版本」、不用「降版」字眼;內部 / API / log 保留 `downgrade`(Q-FW-3 已落定、見 §9) +- **D-FW-3**(防誤觸機制):✅ Design v2.2 §6.1 採「DOWNGRADE」嚴格字面輸入(嚴格 `===` 比對、不接受小寫 / 全形 / 半形空白、雙重保險) +- **D-FW-4**(FW badge 三色閾值):✅ AC-FW-1.1 已明示 4 色閾值(綠 / 黃 / 紅 / 灰)、Design v2.2 §4.2 對齊 +- **D-FW-5**(6 階段中英雙語文案):✅ **採 Design 命名**:preparing / loading / flashing / verifying / done / error(中文文案:準備中 / 載入引導程式 / 寫入韌體 / 驗證中 / 完成 / 失敗)、見 AC-FW-1.2 +- **D-FW-6**(持久 banner 視覺):✅ Design v2.2 §6.3 已落地 + +### 14.2 給 Architect Agent — **大部分已處理** + +- **A-FW-1**(R5-Q9 行號):✅ **已決定**:本檔 §2.1 改為描述式引用、Q-FW-6 已落定 +- **A-FW-2**(driver safety guards):✅ Architect TDD v2.2 §2.1 + §3.3 已對應寫具體 Go interface + `_validate_downgrade_request` +- **A-FW-3**(三平台實機驗證):✅ Architect TDD §11.4 已涵蓋 +- **A-FW-4**(KL630/KL730 wheel 支援度):✅ **已決定**(吸收 M9-6 弱驗證):AC-FW-3.5 延後到 B 階段 M9-10、含 a/b/c 生效條件、見本檔對應段落 +- **A-FW-5**(模組路徑 `server/internal/firmware/`):✅ Architect TDD v2.2 §2.1 對齊 +- **A-FW-6**(與 R5-B4 授權合併):✅ Architect ADR-001 §Compliance 標 `[ ] 與 Kneron 取得 firmware redistribution 授權`、§Related 已連結 R5-B4 + +### 14.3 給 Orchestrator — **追蹤項** + +- **O-FW-1**(與 R5-B4 release blocker 合併):⏳ 待 Orchestrator 統一決定。PM 建議合併(都是 Kneron 智財 + 都是發佈前 gate)、但保留各自具體 scope(firmware vs model 兩個 license 範圍) +- **O-FW-2**(M9-6 強驗證 + AC-FW-3.5 觸發條件):⏳ M9-10 啟動時評估 a/b/c 三條件、任一不滿足 → Orchestrator 派 PM 微調 PRD(KL630/KL730 維持 FW 偵測 only / 不開升降版) + +### 14.4 互審 Minor 處理紀錄 + +| # | 來源 | 內容 | 處理 | +|---|------|------|------| +| M-A1 | Architect TDD §10 R-FW-5 等級「待釐清」| 統一用 P0/P1/P2/P3 分級 | ✅ Architect 修 TDD(PM 不處理)| +| M-A2 | Architect TDD §11.3 缺 KL720 timeout 上界測試 | 加「KL720 升級實測時長 ≤ 200s」測試案例 | ✅ Architect 修 TDD | +| M-A3 | Architect §3.1 API 缺 `notes` / `estimatedDurationSec` 欄位 | 補在 `GET /firmware/versions` response | ✅ Architect 修 TDD | +| M-A4 | TDD §6.2 KL520 KDP1 pid=0x0200 vs KL720 衝突 | Architect 確認後對齊 PRD §1.1 | ⏳ Architect 修 TDD(PM 等對齊結果)| +| M-D1 | Design §9 i18n keys 52 vs PM 估 46 | 採 Design 實際值 52 keys | ✅ 本檔 §11.3 已記「+46 個(estimate)→ 實際 52 個(Design v2.2 §9)」 | +| M-D2 | Design §3.3 「accordion + radio list」vs PRD「dropdown」 | AC-FW-2.3 改「radio list 或同等選擇 UI」 | ✅ 已處理 | +| M-D3 | DOWNGRADE 字串 i18n 化 | Q-FW-8 已落定保留英文字面 | ✅ 已處理 | +| P-MID-1 | 缺體驗指標 | 補 §7.2.1 體驗指標 5 條 | ✅ 已處理 | +| P-MID-2 | PRD 用詞混用「降版」 | Q-FW-3 落定 + US-FW-2 拆 a/b + framing 共識段落 | ✅ 已處理 | +| P-MID-3 | KL520 升級時間 30s vs ≤ 60s | AC-FW-1.7 明示「~30 秒實測 + ≤ 60s 護欄上界」| ✅ 已處理 | +| P-MID-4 | badge 閾值不清 | AC-FW-1.1 補 4 色定義(含灰色狀態未知)| ✅ 已處理 | +| P-LOW-1 | 缺「使用者怎麼發現要降版」US | 標為 v2.3 未來迭代(Workspace inference 失敗時 hint)| ⏳ 暫不處理 | +| P-LOW-2 | Bundle 安裝時間衝擊 | §6.3 補一句 | 見 §6.3 | +| P-LOW-3 | R-FW-12 緩解過抽象 | R-FW-12 改「已具體落地」+ 引用 Design v2.2 §3.3 / §9 | ✅ 已處理 | +| F1-F7 | Architect 自查 7 項必修 | 由 Architect 修 TDD、PM 不直接處理 | ⏳ Architect 端處理中 | + +--- + +## 變更紀錄 + +| 版本 | 日期 | 作者 | 變更 | +|------|------|------|------| +| v2.2-draft | 2026-05-24 | PM Agent | 初稿;翻案 R5-Q9;A + B 兩階段範圍定義;多層 safety net for 一般使用者降版;風險 R-FW-1 ~ R-FW-12 彙整自 Architect research 30/40/41/42;§14 列出 14 個 Design / Architect / Orchestrator 待互審項 | +| v2.2.1 | 2026-05-25 | PM Agent | 吸收三方互審(PM Self / Design / Architect)+ M9-6 弱驗證結果。**主要變更**:①stage 命名統一採 Design(preparing/loading/flashing/verifying)②M9 工時表拆法採 PM(Architect 已同意)③AC-FW-3.5(KL630/KL730 升降版)延後到 B 階段 M9-10、補生效條件 a/b/c、A 階段 KL630/KL730 只做 FW 偵測(無升降版按鈕)④ADR-009 → ADR-001 編號統一⑤R5-Q9 行號改描述式引用、不引用脆弱行號⑥US-FW-2 拆成 US-FW-2a(一般使用者)+ US-FW-2b(進階使用者)、UI 文案 framing 統一中性「韌體管理」「切換到此版本」⑦補 §7.2.1 體驗指標 5 條(升級任務完成率 / 中途放棄率 / badge 點擊率 / 重試率 / SUS 分數)⑧新增 R-FW-13 wheel 三平台版本不一致 + R-FW-14 大小寫繞過⑨補 AC-FW-1.9 graceful shutdown 拒絕⑩badge 4 色定義(補灰色狀態未知)⑪§14 標記哪些已解決 / 哪些 ⏳ 追蹤中。詳見本檔 §14.4 互審 Minor 處理紀錄 | diff --git a/local-tool/.autoflow/02-prd/reviews/pm-review-of-tdd-and-design-v2.2-firmware.md b/local-tool/.autoflow/02-prd/reviews/pm-review-of-tdd-and-design-v2.2-firmware.md new file mode 100644 index 0000000..8e7b1e2 --- /dev/null +++ b/local-tool/.autoflow/02-prd/reviews/pm-review-of-tdd-and-design-v2.2-firmware.md @@ -0,0 +1,200 @@ +# PM 互審報告:Architect TDD v2.2 + Design v2.2 firmware + +> 審查日期:2026-05-24 +> 審查者:PM Agent +> 對應 PRD:`.autoflow/02-prd/features/feature-firmware-management.md` v2.2-draft +> 審查範圍: +> - `.autoflow/04-architecture/v2/firmware-management.md`(TDD v2.2,466 行) +> - `.autoflow/04-architecture/adr/ADR-001-firmware-management.md`(152 行) +> - `.autoflow/03-design/v2/firmware-management.md`(Design v2.2,920 行) + +--- + +## TL;DR + +**整體結論:通過 with Minor + 少數 Major**。三份文件對 PRD 的 4 個 user story(US-FW-1 ~ US-FW-3)與成功指標的覆蓋度極高、R5-Q9 翻案的範圍切割與 PRD 完全一致、ADR-001 寫得清楚可追溯。 + +但有 **3 個 Major 問題**需要 Architect / Design 修改後才能 merge: +1. PRD 寫了 US-FW-2 包含「進階使用者切換 FW 版本」的 user story(含「就是想試試看」「測試環境」等情境),但 Design 文案策略卻是「**對一般使用者過於負面**、用『版本切換』中性詞」——這兩個 framing 的隱含 persona 不一致、PM 需與 Design 對齊 +2. ADR-001 編號錯誤:PRD 引用的是 ADR-009(`feature-firmware-management.md` §2.5 / §11.4),但實際檔名是 ADR-001——需統一 +3. R5-Q9 行號爭議(L776 vs L854)PM 在 PRD 明示要 Architect cross-check、但 ADR-001 + TDD 沒有處理這點 + +另外有 **8 個 Minor**(建議改但不阻擋)、4 個建議性回饋。詳見下方分項。 + +--- + +## 對 Architect TDD 的審閱 + +### 🟢 通過項 + +1. **§1.1 痛點對應 PRD §1.1 完全一致**:3 個列出的痛點(拿到 KDP1 不能用 / KL520 Error 15 / KL630/KL730 偵測不到)與 PRD §1.1 + §1.2 對齊 +2. **§1.2 範圍邊界對應 PRD §2.4 完全一致**:「升級到官方 KDP2 標準版本」做、「使用者燒任意 model 到 flash」繼續砍——R5-Q9 翻案的範圍切割對齊 PRD §2.4 表格 +3. **§3 API 設計覆蓋 PRD US-FW 全部 4 個 user story**: + - `GET /api/devices` 衍生欄位 → AC-FW-1.1 FW badge + - `POST /api/devices/:id/firmware/upgrade` → AC-FW-1.2 升級 + - `GET /api/devices/:id/firmware/versions` → AC-FW-2.3 版本列表 + - `POST /api/devices/:id/firmware/downgrade` + `confirmToken` → AC-FW-2.6 / AC-FW-2.9 強制二次確認 + - WebSocket room `firmware:` → AC-FW-1.2 progress modal +4. **§3.3 錯誤碼涵蓋 PRD 8.1 / 8.2 R-FW-1 ~ R-FW-12 對應 mitigation**:6 個錯誤碼(`FW_DEVICE_BUSY` / `FW_VERSION_NOT_FOUND` / `FW_INVALID_DIRECTION` / `FW_NO_CONFIRM_TOKEN` / `FW_UPGRADE_FAILED` / `FW_UPGRADE_BRICK_RISK`)與 PRD §8.1 / §8.2 風險清單對齊 +5. **§5.2 降版流程完整對應 AC-FW-2.6 ~ AC-FW-2.10**:二次確認 + DOWNGRADE 輸入 + 不可關 modal + persistent banner + driver guards 都有設計 +6. **§8.1 watchServer Error state 解耦對應 AC-FW-1.8**:明示 FW 升降版失敗不觸發 server Error state、與 PRD §8.3「衝突已釐清項」一致 +7. **§8.2 KL520 reset bug 對應 PRD §1.1 痛點 #2**:明示「升級成功後 needsReset=true、下次連線走完整 reset、避開 Error 15」——這正是 2026-04-21 fix 機制的延續 +8. **§9 工時 15.5 人天對齊 PRD §10.3**:A 5 + B 10.5 = 15.5、milestone 切分 M9-1 ~ M9-13 一致 +9. **§10 風險表 R-FW-1 ~ R-FW-12 + R-TAR-1 ~ R-TAR-4 對齊 PRD §8.1 / §8.2**:除編號略有偏移外、實質內容對齊 +10. **§11 測試策略涵蓋 AC-FW-1.8(watchServer 不誤判)+ 既有 KL520/KL720 回歸**:§11.4 明示「watchServer 機制不會把 FW timeout 誤判為 server 死亡」、且涵蓋 KL520 / KL720 既有 E2E 回歸 + +### 🟡 Minor(不阻擋、建議改) + +| # | 章節 | 問題 | 建議修法 | +|---|------|------|---------| +| M-A1 | §10 R-FW-5 | 風險表內欄位 `等級` 寫「待釐清」、不是 PRD §8.1 用的「P0(發佈 gate)」 | 統一用 PRD 的 P0/P1/P2/P3 分級語彙、或在 §10 表頭加註「等級 = PRD R-FW 對應的優先級」說明 | +| M-A2 | §11.3 異常路徑測試 | 缺一條「升級 timeout(mock 180s 不回)」對應 AC-FW-1.7「KL720 預估 180 秒」的明確上界測試 | 加一行「KL720 升級實測時長 ≤ 200s(PRD §7.2 護欄)」測試案例 | +| M-A3 | §3.1 API 端點清單 | 表格沒有列出 PRD AC-FW-2.3「版本說明文案」「預估時間」這些 metadata 從哪個 API 取 | 在 `GET /firmware/versions` 的 response 範例中明示是否含 `notes` / `estimatedDurationSec` 欄位(Design §3.3 wireframe 顯示了「2024-08 發行」「與舊模型相容」等資訊、後端需提供) | +| M-A4 | §6.2 chip 判斷 | KL520 / KL720 / KL630 / KL730 product_id 都列了、但 PRD §1.1 痛點表列「KDP1 legacy pid=0x0200」、TDD §6.2 卻把 0x0200 對到 KL720——這是 KL520 KDP1 legacy 還是 KL720?需與 PRD 痛點表對齊 | Architect 互審時確認:0x0200 到底是 KL520 KDP1 legacy(PRD §1.1)還是 KL720(TDD §6.2 L322)。若兩者皆是不同 product_id、PRD §1.1 痛點表應更正為「KDP1 legacy pid=0x0100」或實際正確值 | +| M-A5 | §9 M9-6 「純研究、Architect 自身產出、不過 Reviewer」 | 與 PRD Q-FW-2 「結論定 B 階段 scope」存在關聯——若 SDK 驗證結論是「不支援」、需重派 PM 微調 PRD(PRD §14.2 A-FW-4),但 TDD 沒寫此 reflow 條件 | §9「Reviewer 切點」段落補一條:「M9-6 結論若觸發 AC-FW-3.5 降級條件,須回 Orchestrator 重派 PM 微調 PRD 後再啟動 M9-7」 | +| M-A6 | §13.1 「PM 互審注意」 | Architect 列了 4 個 PM 互審注意點、但漏列 PRD §14.2 A-FW-4 / A-FW-5 / A-FW-6 的 6 個 Architect 待回覆項——PM 不知道哪些是 Architect 已回覆、哪些待回 | §13.1 補一節「PM PRD §14.2 待回覆項對應」列出 A-FW-1 ~ A-FW-6 各自在本 TDD 哪一節已回覆(或標「未處理、留 follow-up」) | + +### 🟠 Major(建議改後 merge) + +| # | 章節 | 問題 | 建議修法 | +|---|------|------|---------| +| MJ-A1 | 整檔 ADR 編號 | PRD §2.5 + §11.4 明示「ADR-009-firmware-management」、但 Architect 實際檔名是 `ADR-001-firmware-management.md`——這是專案歷史上的第幾個 ADR?與 PRD 引用差 8 號需要解釋 | 三方需對齊:(1) 改 ADR 檔名為 `ADR-009-firmware-management.md`、或 (2) PRD §2.5 / §11.4 改為引用 `ADR-001`。PM 傾向 (1),因為「009」對應 R5 第 9 個議題、語意較豐富。但若 ADR 編號規則是「按時間順序、本專案第 1 個 ADR」、那 PRD 該改為 ADR-001。需 Architect 確認 ADR 編號規則後統一 | +| MJ-A2 | §1 (整體) | TDD 沒處理 PRD §2.1 標明的「R5-Q9 行號 L776 vs L854 不一致、Architect 互審時 cross-check」 | TDD §1(或新增 §1.4)補一段「R5-Q9 行號釐清」:說明 Architect 確認 progress.md 當前 L854 為 R5 第二輪 Q9 條目、L776 是 research summary 引用的歷史快照行號、決策本身內容一致 | + +### 🔴 Critical(必須改、阻擋 merge) + +無。Architect TDD 與 PRD 的需求覆蓋度足以推進開發。 + +--- + +## 對 Design Spec 的審閱 + +### 🟢 通過項 + +1. **§1 定位職責對齊 PRD §3.2 + AC-FW-2.1**:明示「韌體管理在 Settings 第 5 分頁、不在 Devices 頁主流程」、避免誤觸——與 PRD §4 user story 一致 +2. **§3.1 ~ §3.3 wireframe 完整覆蓋 US-FW-1 + US-FW-2**:裝置卡片 + FW badge 三色 + 「版本切換」accordion 設計符合 PRD AC-FW-1.1 / AC-FW-2.3 +3. **§4 Devices 頁 FW Badge 對應 AC-FW-1.1**:綠 / 黃 / 紅三色 + tooltip + deep-link ⚙ icon、與 PRD US-FW-1 直接對齊 +4. **§5 升級流程完整覆蓋 US-FW-1 全部 AC**: + - §5.1 確認 modal → AC-FW-1.2 + - §5.2 進度 modal 不可中斷 → AC-FW-1.5 + - §5.3 6 stage 對應 → PRD AC-FW-1.2「全程顯示階段」+ TDD §4.3 + - §5.4 成功 toast → AC-FW-1.3「自動關閉 + 觸發 rescan + badge 變綠」 + - §5.5 失敗復原 → §7 +5. **§6.1 降版二次確認 modal 對應 AC-FW-2.5 + AC-FW-2.6 + AC-FW-2.7 + AC-FW-2.8 全部**:警告語 4 條、輸入 DOWNGRADE 字串、不可外部關閉、進行中無取消按鈕——一條一條都對上 PRD 的 AC +6. **§6.2 KDP1 額外警告**:超出 PRD AC-FW-2.5 既有 4 條警告語、Design 主動加「KDP1 不支援多模型」這條——這個延伸符合 PRD US-FW-2 第 2 個情境「跟某個 third-party tool 不相容、要回 KDP1」的精神 +7. **§7 失敗復原 8 種類型對應 PRD AC-FW-1.4 + AC-FW-2.8**:每種 stage 失敗都有 friendly message + 復原行動、超出 PRD 既有要求 +8. **§10 A11y 對應 PRD US-FW-2 一般使用者**:focus trap、aria-live、role="alertdialog"、reduced motion——這對「面向一般使用者」的承諾是必要的 +9. **§11.2 新增 6 個 component-level tokens** 不是亂增、有推導表與對比比率驗證 +10. **§12 R-FW 風險的 Design 對策**:對應 PRD §8.2 R-FW-11 「一般使用者誤觸降版 brick 風險」、列出 7 條 mitigation 全部對應 PRD AC 條目 +11. **§14.4 給 Orchestrator 懸而未決 3 條**:對應 PRD §9 未解決問題、Design 補上 3 個 PRD 沒提到的(i18n 化 / metadata 來源 / 控制台關閉攔截)——這是好的延伸 + +### 🟡 Minor(不阻擋、建議改) + +| # | 章節 | 問題 | 建議修法 | +|---|------|------|---------| +| M-D1 | §9 i18n keys 52 個 | PRD §10.2 引用 research 42 §5.6 估算 46 keys、Design 實際 52 keys——多 6 keys 是合理的(含 settings.tabs.firmware + Devices badge tooltip 4 keys + 1-2 個技術資訊)| 不用改、但 PRD §10.2 應在下次補丁更新為 52 keys、或在當前 PRD 加註「實際以 Design §9 為準」 | +| M-D2 | §3.3 「版本切換」accordion | accordion 樣式對應 PRD AC-FW-2.3 「dropdown」,Design 改用 radio list、§3.3 末段已說明理由(< 3 個版本、a11y 友善)——這是好的延伸但 PRD AC-FW-2.3 文字仍寫「dropdown」 | PRD §4 US-FW-2 AC-FW-2.3 應在下次補丁更新為「radio list 或同等選擇 UI」、或 PM 採納 Design 決定後改 PRD | +| M-D3 | §6.1 「DOWNGRADE」字串 i18n 化 | Design §14.4 第 4 點懸而未決提到、PRD §9 Q-FW-3 「降版」用詞策略已說明 UI 不用「降版」字眼但 PRD 沒明示 DOWNGRADE 字串本身要不要 i18n | PRD §9 應在下次補丁新增 Q-FW-8「DOWNGRADE 字串 i18n 化」對應 Design §14.4 第 4 點 | +| M-D4 | §3.1 裝置卡片配色 | 圓點 🔴 / 🟡 / 🟢 對應 PRD AC-FW-1.1 三色 badge、但 Design 把「KDP1」+「has newer」都用紅色(Design L101)vs PRD AC-FW-1.1 寫「黃 = 比 current 舊但可升」、「紅 = legacy KDP1 或損毀」——Design 表格分了 3 colour 但 wireframe 圖示 KDP1 用紅、PRD 文字寫「v2.1.0」應為黃。需確認 wireframe legend 是否清楚 | Design wireframe 加註釋「KDP1 → 紅 / v2.1.0 較舊 → 黃 / v2.2.0 current → 綠」,避免讀者只看 wireframe 不看 §3.1 表格時誤解 | +| M-D5 | §11.2 token Dark 模式對比 | Design 自己標「Architect 互審重點:請確認 Dark 模式下 `legacy.fg` 用黑色對紅底對比是否真的足夠(推算 4.8:1、但實作時需用 contrast checker 工具驗證)」 | 這個是 Architect 互審的事、不是 PM 互審範圍。但 PM 確認:對比 4.8:1 達 WCAG AA(≥ 4.5:1)、不違反 PRD 對 a11y 的承諾。Design 可以將 §11.2 結尾「Frontend 需用 contrast checker 工具驗證」改為更明示的 AC(如「實作後 Frontend M9-12 驗收必跑 axe-core / Lighthouse a11y 測試、對比比率必達 4.5:1」) | + +### 🟠 Major(建議改後 merge) + +| # | 章節 | 問題 | 建議修法 | +|---|------|------|---------| +| MJ-D1 | §2.1 「分頁名稱不能叫『降版』——對一般使用者過於負面」 vs PRD §5.1 / US-FW-2 | **這是本次互審最大的 framing 分歧**:PRD §5.1 引用 architect research 42 結論、明示「手動降版面向一般使用者」、§5.3 列出 5 個情境(含「就是想試試看」「測試環境」)。Design §2.1 卻說「降版對一般使用者過於負面、一律稱『韌體』或『韌體管理』」——這兩個 framing 的隱含 persona 不一致:PRD 把一般使用者當「有能力理解風險的進階使用者」、Design 把一般使用者當「需要保護不要看到負面詞彙的非技術使用者」。需 PM + Design 對齊「一般使用者」的具體定義 | **建議方案**:PRD + Design 對齊到 Design 立場(UI 文案中性、`downgrade` 只留技術文件)、因為 R5 Persona 表已明示 P1 是 FAE / P2 是「外部開發者」、但實際 dongle 也會給「跟著開發者一起使用的客戶現場 demo 觀察者」、後者並非技術人員。PRD §5.1 H3 假設「藏在 dev mode 反而讓真正需要降版的人找不到」仍成立、Design §2.1 中性文案不違反此假設。**具體修法**:PRD §9 Q-FW-3 「降版這個詞是否用於 UI 文案」應從「待 Design Agent 最終決定」改為「已決定:UI 用『版本切換』中性詞、技術文件保留 downgrade」,並在 PRD §4 US-FW-2 敘述中將「按下『降版』按鈕」改為「按下『切換到此版本』按鈕」 | +| MJ-D2 | §3.3 第 3 個 user story(「進階使用者切換 FW 版本」)的 PRD 對應 | Design §14.4 第 5 點 + §3.3 accordion 設計都暗示存在「進階使用者主動切版本」的 user story、但 PRD §4 只有 US-FW-1(自動升級)+ US-FW-2(降版 + 多版本切換)+ US-FW-3(KL630/KL730)——PRD 沒有獨立的「進階使用者切換 FW 版本」US。Design 把這個假設藏在「accordion」設計中,但若 PM 沒明示這個 user story、可能造成實作時 Frontend 缺少對應的 AC 驗收標準 | **建議方案**:PM 在下次 PRD 補丁將 US-FW-2 拆分為兩個:(1) **US-FW-2 一般使用者主動切版本**(含降版到舊版 / KDP1 兩個情境)+ (2) **US-FW-2.5 進階使用者跨版本切換**(含「升回上一個版本」「測試環境切版本」等情境)。這樣 Design 的「accordion + 中性文案」策略才有對應的 PRD source-of-truth。**或**:PRD §4 US-FW-2 敘述加一段「本 user story 同時覆蓋進階使用者主動跨版本切換的情境(含升回上版 / 測試環境切版本)、UI 上以中性『版本切換』詞彙呈現、不區分『升 / 降』」 | + +### 🔴 Critical(必須改、阻擋 merge) + +無。Design Spec 與 PRD 的需求覆蓋度足以推進開發。MJ-D1 + MJ-D2 雖是 Major、但屬 framing 對齊問題、不是設計錯誤、可在下次 PRD 補丁修正後直接 merge Design Spec。 + +--- + +## 對 ADR-001 的審閱 + +### 結論:通過 with 1 個 Minor + 對齊 ADR 編號的 Major(已在 TDD 章節列出 MJ-A1) + +| 項 | 評估 | +|----|------| +| Status: Accepted | ✅ 對齊使用者 2026-05-24 拍板紀錄 | +| Context 引用歷史紀錄正確嗎? | ✅ 4 個痛點背景對齊 PRD §1.1 / progress.md;R5-Q9 砍 flash 歷史決策推測的 4 個原因與 PRD §2.2 一致 | +| Decision / Consequences 跟 PRD 結論一致嗎? | ✅ 5 項決策(A+B 一次做 / R5-Q9 範圍切割 / KneronPLUS Python C API / 選項 C metadata / 保守 +7MB)全部對齊 PRD §3 / §6 | +| Alternatives Considered 完整嗎? | ✅ 列了 5 個替代方案、含 DFUT.exe / dev mode only / 多版本目錄選 A B C / 等 A 階段驗證再評估 B——這是好的留痕 | +| Compliance checklist | ✅ 含 firmware redistribution 授權標未完成、與 PRD §9 Q-FW-1 一致 | + +### 🟡 Minor + +| # | 章節 | 問題 | 建議修法 | +|---|------|------|---------| +| M-ADR1 | Related 表 | 列了「R5-B4」「R5-E」「2026-04-21 commit」「watchServer」「research-kl520-fw-management/」——但沒列「`feature-firmware-management.md`」(PRD)| 加一行「`feature-firmware-management.md` / PRD v2.2 對應 user story 與成功指標」 | + +### 🟠 Major(與 TDD 互審共用) + +MJ-A1:ADR 編號 ADR-001 vs PRD 引用的 ADR-009 不一致——詳見 Architect TDD 互審 MJ-A1。 + +--- + +## 結論 + +| 文件 | 結論 | +|------|------| +| Architect TDD v2.2 | ✅ 通過 with 6 Minor + 2 Major(MJ-A1 ADR 編號 + MJ-A2 行號 cross-check) | +| Design Spec v2.2 | ✅ 通過 with 5 Minor + 2 Major(MJ-D1 「降版」文案 framing + MJ-D2 user story 拆分) | +| ADR-001 | ✅ 通過 with 1 Minor + 共用 MJ-A1 編號修正 | +| 整體 | **通過 with Major 修正**——三份文件對 PRD 需求覆蓋度高、R5-Q9 翻案的範圍切割三方一致、ADR 留痕完整。需 Architect 統一 ADR 編號、PM 在下次 PRD 補丁對齊 Design 的「中性文案」立場 + 拆分 user story。所有 Major 修完後即可 merge、進 M9-1 開發。 | + +--- + +## 給 Orchestrator 的建議 + +### 建議派 Architect 修改項 + +| # | 項目 | 工作量 | +|---|------|-------| +| 1 | **MJ-A1 ADR 編號統一**:與 Architect 確認 ADR 編號規則後、決定 `ADR-001` 還是 `ADR-009`、修改檔名 + 內部引用 + 通知 PM 同步改 PRD §2.5 / §11.4 | 0.1 人天 | +| 2 | **MJ-A2 R5-Q9 行號 cross-check**:TDD §1 補一段釐清 L776 vs L854 | 0.1 人天 | +| 3 | M-A1 ~ M-A6(Minor)| 0.2 人天(或全部 留為 follow-up)| + +**建議**:Architect 修 2 個 Major 後即可 merge。Minor 全部留 follow-up、在 M9-1 啟動前的 prep 階段一次處理。 + +### 建議派 Design 修改項 + +| # | 項目 | 工作量 | +|---|------|-------| +| 1 | **MJ-D1 對齊 PRD「降版」文案立場**:等 PM 修 PRD §9 Q-FW-3 後、Design 不用改檔(Design 立場已是中性、PRD 對齊到 Design 即可)| 0 人天(Design 端)| +| 2 | **MJ-D2 user story 拆分**:等 PM 修 PRD §4 US-FW-2 後、Design 在 §1 加註對應 PRD 哪個 user story、確保未來查閱可追溯 | 0.1 人天 | +| 3 | M-D1 ~ M-D5(Minor)| 0.2 人天(或全部留為 follow-up)| + +**建議**:Design 等 PM 改完 PRD 後再做小幅對齊、目前 Design Spec 不需要主動改。 + +### 建議派 PM(我自己)修改項 + +| # | 項目 | 工作量 | +|---|------|-------| +| 1 | **修 PRD §2.5 / §11.4 ADR 編號**:等 Architect 統一後同步改 | 0.1 人天 | +| 2 | **修 PRD §9 Q-FW-3「降版」用詞**:從「待 Design 決定」改為「已決定 UI 用中性『版本切換』、技術文件保留 downgrade」| 0.1 人天 | +| 3 | **修 PRD §4 US-FW-2 拆分(或加註覆蓋進階使用者切版本情境)** | 0.2 人天 | +| 4 | **修 PRD §10.2 i18n keys 數量**:從 46 改為 52 | 0.05 人天 | +| 5 | **修 PRD §4 US-FW-2 AC-FW-2.3「dropdown」→「radio list 或同等」** | 0.05 人天 | +| 6 | **新增 PRD §9 Q-FW-8「DOWNGRADE 字串 i18n 化」** | 0.05 人天 | + +**合計**:PM 後續補丁工作量 ~0.55 人天。 + +### 互審 follow-up 流程建議 + +1. **本輪先收尾**:Orchestrator 收三份互審報告(PM / Architect / Design)、評估分歧點 +2. **Architect 修 ADR 編號 + 行號 cross-check**(2 個 Major)→ 通知 PM +3. **PM 補 PRD 對齊 4 個 Major 對應項**(ADR 編號 / Q-FW-3 / US-FW-2 / i18n keys 數量)→ 通知 Design +4. **Design 在 §1 加註對應 PRD user story 後再 merge** +5. 整體進度推進到 M9-1 啟動 + +**不阻擋的 follow-up**:所有 Minor(M-A1 ~ M-A6 + M-D1 ~ M-D5 + M-ADR1)可在 M9-1 啟動前 prep 階段一次處理、或直接留到 M9-13 三平台驗收後再回頭補。 + +--- + +## 變更紀錄 + +| 版本 | 日期 | 作者 | 變更 | +|------|------|------|------| +| v1 | 2026-05-24 | PM Agent | 初版互審報告;3 個 Major + 11 個 Minor + 4 個建議;整體通過 with Major 修正 | diff --git a/local-tool/.autoflow/03-design/design-spec-v2.md b/local-tool/.autoflow/03-design/design-spec-v2.md index 0cd8a83..3fe4372 100644 --- a/local-tool/.autoflow/03-design/design-spec-v2.md +++ b/local-tool/.autoflow/03-design/design-spec-v2.md @@ -1,7 +1,8 @@ # visionA-local 設計規格 v2(索引) > Design Agent · 第五輪正式規格 · 初版 2026-04-14 -> **目前版本:v2.1(2026-04-14 補丁)** — 吸收 Architect 交叉審閱 Major 1+2 / Minor 1-5 修正 + R5-D1/D2/D3 / R5-E 追加決策 +> **目前版本:v2.2(2026-05-24 補丁)** — 吸收 R5-Q9 翻案、新增 Kneron Dongle FW 管理規格(升級 + 版本切換、面向一般使用者) +> 前一版本:v2.1(2026-04-14 補丁)— 吸收 Architect 交叉審閱 Major 1+2 / Minor 1-5 修正 + R5-D1/D2/D3 / R5-E 追加決策 > 本版依 **R5 決策**重構:visionA-local 從「Wails 跑 Next.js 的單一桌面 app」轉為「**Wails Server Control Panel + 瀏覽器 Web UI**」雙 UI 架構。 > 本文件為 v2 索引檔,各章節詳細內容見 `v2/` 子檔。v1(`design-spec.md` + `spec/`)仍保留作為基準參考,未來的實作以 v2 為準。 @@ -36,6 +37,7 @@ | v2.4 | First-Run 流程重定義 | `v2/first-run-update.md` | 砍 Mock 模式選擇步驟、自動開瀏覽器的起手流程圖 | | v2.5 | Settings 頁更新 | `v2/settings-update.md` | 新增「啟動時自動開啟瀏覽器」toggle、Linux 預設 OFF、落地 `preferences.json`、砍 Mock 相關設定 | | **v2.6** | **啟動進度面板**(v2.1 新增) | **`v2/startup-progress.md`** | **R5-E 階段化啟動進度面板:6 階段 wireframe、中英雙語文案、20 秒卡頓提示、60 秒 timeout Error 流程** | +| **v2.7** | **韌體管理**(v2.2 新增) | **`v2/firmware-management.md`** | **Kneron dongle FW 升級 + 版本切換完整規格:Settings 新分頁、Devices 頁 FW badge(紅/黃/綠 + deep-link)、二次確認流程(輸入 DOWNGRADE)、52 個 i18n keys、6 個新 component token、R-FW-11 設計緩解** | --- @@ -86,6 +88,23 @@ --- +## v2.1 → v2.2 差異總覽(2026-05-24 補丁輪) + +v2.2 是吸收 R5-Q9 翻案(FW 管理面向一般使用者)後的補丁,新增 Kneron dongle FW 升級 + 版本切換的完整設計規格。**不改變 R5 雙 UI 架構立論**、只新增功能模組。 + +| 面向 | v2.1 | v2.2(2026-05-24 補丁)| 來源 | +|------|------|---------------------|------| +| Settings 分頁數 | 4(一般 / 硬體 / 模型 / 進階) | **5**(一般 / 硬體 / **韌體** / 模型 / 進階) | R5-Q9 + architect 42 | +| Devices 頁 FW 顯示 | 純文字 `FW 2.1.0` | **pill badge**(紅 / 黃 / 綠三色)+ deep-link ⚙ icon | R5-Q9 第 5 點 | +| FW 升級 UX | 未設計 | **單步驟確認 + 進度 modal**(不可中斷) | architect 30 §M9-4 | +| FW 降版 UX | 未設計 | **二次確認**(輸入「DOWNGRADE」字串)+ 進度 modal + 全螢幕 hover 攔截 | architect 42 §5.3 | +| 失敗復原 UX | 未設計 | **8 種失敗類型對應 friendly message + 復原行動** | architect 42 §5.5 | +| 新增 i18n keys | — | **52 keys**(zh-TW + en) | 本檔 `v2/firmware-management.md §9` | +| 新增 component tokens | — | **6 個 fw-badge token**(current / older / legacy × bg/fg) | 本檔 `v2/firmware-management.md §11.2` | +| UI 用語策略 | — | UI 一律稱「韌體管理」/「版本切換」(中性詞)、code/log/技術文件仍稱 downgrade | architect 42 §1.1 | + +--- + ## v2 → v2.1 差異總覽(2026-04-14 補丁輪) v2.1 是 v2 三方互審後的修正補丁,不改變 R5 雙 UI 架構立論,只處理 Architect 互審發現 + R5-D / R5-E 追加決策。 @@ -118,6 +137,11 @@ v2.1 是 v2 三方互審後的修正補丁,不改變 R5 雙 UI 架構立論, - (b) 階段 6 WebSocket 連線被安全軟體擋的 Error 說明是否要特別提示 - (c) 使用者按 Retry 的語意:重置整個啟動流程 vs 重試當前階段(Design 建議前者) +**v2.2 新增懸而未決**(來自 `v2/firmware-management.md §14.4`): +4. **降版 modal 字串「DOWNGRADE」未來 i18n 化處理**:當前 Design 規格要求所有語系使用者皆輸入字面字串 `DOWNGRADE`(en)。若未來改 i18n(如中文使用者輸入「降版」),需與 Architect / Frontend 確認後端 `confirmToken` 是否同步調整(architect 42 §2.3 後端固定接受 `confirmToken: "DOWNGRADE"`)。Design 建議**短期維持英文字串**(跨語言一致、避免後端多語對應)。 +5. **bundled 版本「發布日期」資料源**:firmware-management.md §3.3 範例顯示「2024-08 發行」等文案,但 architect 42 §2.1 `FirmwareVersion.ReleaseDate` 為 optional。需 Backend 在 bundle firmware 時準備 metadata(每個 version 目錄附 `META.json` 含 releaseDate / notes)。metadata 缺則 UI fallback 為不顯示日期。 +6. **降版進行中關閉 Wails 控制台視窗的攔截邏輯**:依 R5-2 控制台關閉 = 結束 server。降版進行中關控制台 = 中斷降版 = 可能 brick。Frontend / Backend 是否需要在控制台側偵測「降版進行中」並擋下關閉動作?建議 Architect 補充。 + --- **下一步:** diff --git a/local-tool/.autoflow/03-design/reviews/design-review-of-prd-and-tdd-v2.2-firmware.md b/local-tool/.autoflow/03-design/reviews/design-review-of-prd-and-tdd-v2.2-firmware.md new file mode 100644 index 0000000..ab93865 --- /dev/null +++ b/local-tool/.autoflow/03-design/reviews/design-review-of-prd-and-tdd-v2.2-firmware.md @@ -0,0 +1,476 @@ +# Design 互審報告 — PM PRD + Architect TDD + ADR-001(v2.2 Firmware) + +> 審閱者:Design Agent +> 審閱日期:2026-05-24 +> 審閱對象: +> - PM:`.autoflow/02-prd/features/feature-firmware-management.md`(v2.2-draft, 523 行) +> - Architect TDD:`.autoflow/04-architecture/v2/firmware-management.md`(v2.2, 604 行) +> - Architect ADR:`.autoflow/04-architecture/adr/ADR-001-firmware-management.md`(v1.0, 210 行) +> 對照基準:`.autoflow/03-design/v2/firmware-management.md`(Design v2.2, 920 行) + +--- + +## TL;DR + +**整體評估**:🟢 三份產出與 Design 整體一致、可進 M9-12 Frontend 實作。共找出 **13 個對齊點**: +- **🔴 嚴重(需互審回合解決)**:1 個 — Architect TDD 狀態機名稱與 Design 不一致(A-MISMATCH-1) +- **🟠 中等(需 PM / Architect 補回應)**:4 個 — PM 缺 NPS / 任務完成率指標、PRD 沒明示「降版」用詞策略、Architect 沒解 graceful shutdown 拒絕、Architect 缺 token 對比實測 +- **🟡 輕微(建議補但不阻塞)**:5 個 — PM 沒列「使用者怎麼知道要降版」user story、PRD 沒提 Bundle 多下載 X 秒、Architect ADR Alternatives 缺一條 Design 視角、PM 對 R-FW-12 不夠具體、PRD §10 KL520 升級時間估算不一致 +- **🟢 對齊良好**:3 個 — 6 個互審待確認點中 4 個已解、API/UI DisplayName 對齊、WebSocket progress event schema 足夠 + +**結論**:建議先解 🔴 A-MISMATCH-1(狀態機對齊),其他 🟠 在實作前的 polish 階段補。**不阻塞 M9-1 ~ M9-5 A 階段啟動**(A 階段不涉及降版 UI、6 個對齊點都是 B2 才會踩到)。 + +--- + +## 一、對 PM PRD 的審閱 + +### 1.1 對齊良好(🟢) + +#### 🟢 P-OK-1:6 個 Architect 互審待確認點 PM 已涵蓋 3 個 + +PM PRD §14.2 列了 6 個給 Architect 的互審項(A-FW-1 ~ A-FW-6),其中: +- A-FW-2(driver safety guards)→ Architect TDD §6.1 + §5.2 已對應寫具體 dispatch 與 `_validate_downgrade_request` +- A-FW-5(模組路徑 `server/internal/firmware/`)→ Architect TDD §2.1 已對應 +- A-FW-6(R-FW-5 與 R5-B4 合併)→ Architect TDD §8.4 已對應 + +Design 視角確認:PM 給 Architect 的問題、Architect 都回答了。**對齊 OK**。 + +#### 🟢 P-OK-2:「降版面向一般使用者」假設(§5)的支持證據完整 + +PM §5.1 列 4 個假設(H1-H4)+ §5.3 5 種降版情境,Design 視角檢核: +- 4 個假設都對齊 R5 Persona 定義(P1 FAE / P2 開發者) +- 5 種情境覆蓋 Design 設計的 UX 流程(Design §6 二次確認 modal、§7 失敗復原都針對這 5 種使用者預期) +- UR-1 ~ UR-4 user research 待驗證項合理(Beta 階段 / post-launch 6 個月追蹤) + +**對齊 OK**,Design 對 PM 的假設沒有體驗面異議。 + +#### 🟢 P-OK-3:AC-FW-2.5 二次確認 modal 警告語 4 條與 Design §6.1 對齊 + +PM AC-FW-2.5 列 4 條警告語: +- 「降版可能導致現有 model 無法運作」→ Design §6.1 風險列表第 1 點「部分新版 .nef 模型無法載入」 +- 「降版過程不可中斷、否則裝置可能損壞」→ Design §6.1 風險列表第 3 點 + §6.3 進度 banner +- 「降版完成後可能需要重新插拔裝置」→ Design §6.4 toast「可能需要重新插拔」 +- 「請確認版本相容性、降版至 KDP1 的舊版會限制可用功能」→ Design §6.2 KDP1 額外紅色 banner + 多 1 條風險 + +**4 條警告語 100% 對應**。Design 用詞略不同(「.nef 模型」vs 「現有 model」),但語意一致、Design 用詞更精準。 + +### 1.2 中等問題(🟠,需 PM 補) + +#### 🟠 P-MID-1:成功指標缺「使用者感知體驗指標」 + +**問題**:PM §7 列 2 種指標(北極星 5 分鐘首次推論達成率 + 次要指標如升級成功率 ≥ 95% / Brick < 0.1%),**全部是技術 / 業務指標**、沒有對應使用者體驗的指標。 + +**Design 視角缺漏**: +- 沒有 **「降版任務完成率」**(使用者點「版本切換」→ 真正完成切換的比例。可能很多人在二次確認 modal 階段就放棄) +- 沒有 **「中途放棄率」**(多少使用者打到一半「DOWNGRADE」就取消、暗示 UX 過度恐嚇) +- 沒有 **「FW badge 點擊率」**(Devices 頁 ⚙ icon / badge 點擊後是否真的進 Settings 韌體分頁,反映 Design IA 是否讓使用者找得到) +- 沒有 **使用後 NPS / SUS 分數**(特別是 B2 階段一般使用者降版流程的可用性) + +**建議**:PM 在 §7.2 加 4-5 個體驗指標。範例: +``` +| 指標 | 目標 | +|------|------| +| 升級任務完成率(modal 開啟 → 完成)| ≥ 85% | +| 二次確認 modal 中途放棄率 | 50-70%(合理區間、太低暗示 UX 不夠恐嚇、太高暗示嚇跑使用者)| +| Devices 頁 FW badge 點擊率 | ≥ 30%(只算紅 / 黃 badge)| +| B 階段 SUS 分數(5 人 usability test)| ≥ 65 | +``` + +**阻塞性**:不阻塞 A 階段、但 B 階段上線前應補(不然沒指標可衡量 UR-1 ~ UR-3)。 + +#### 🟠 P-MID-2:PRD 沒明示「降版」用詞策略、可能與 UI 矛盾 + +**問題**: +- PM §14.1 D-FW-2「『降版』這個詞在 UI 上是否使用」標為 Design 待定 +- PM 自己文件多處用「降版」(§4 US-FW-2 標題就是「一般使用者主動切版本」、但內文反覆用「降版」) +- Design 已明確採「韌體 / 版本切換」中性詞、UI 不用「降版」(Design §2.1 + §3 範例 wireframe 全部用「版本切換」) + +**體驗面風險**:如果 PM PRD 的 user story 文字用「降版」、未來測試人員 / 文件譯者可能誤以為 UI 應該叫「降版」、造成 UI 文案改錯方向。 + +**建議**:PM 在 §14.1 D-FW-2 加註「Design 採『韌體 / 版本切換』、PRD 後續更新時 user-facing 描述應同步」。或在 §4 user story 標題明示「**進階使用者**主動切版本(內部 / 技術文件用 downgrade、UI 用『版本切換』)」。 + +**阻塞性**:不阻塞 A 階段、但 B 階段 PM 應明示。 + +#### 🟠 P-MID-3:PRD §10 KL520 升級時間估算不一致 + +**問題**: +- AC-FW-1.7:「KL520 升級預估 30 秒;KL720 預估 180 秒」 +- §7.2 次要指標:「FW 升降版平均時長:KL520 ≤ 60s / KL720 ≤ 200s」 +- AC-FW-1.7 30s vs §7.2 ≤ 60s 不一致 + +**Design 視角影響**:Design §5.5 進度 modal 顯示「預估剩餘 X 秒」、這個數字從哪裡來?如果以 AC 30s 為基準、實際拖到 50s 使用者會誤以為「failed」;如果以 60s 為基準、實際 30s 結束又會讓使用者懷疑「真的有寫到 flash 嗎?」 + +**建議**:PM 統一兩處數字、Design 建議用 §7.2 的上限(≤ 60s for KL520 / ≤ 200s for KL720)作為「預估剩餘」基準、給 UX 緩衝。 + +**阻塞性**:不阻塞 A 階段啟動、但 Frontend 實作 §5.5 進度 modal 前要釐清。 + +#### 🟠 P-MID-4:PM §14.1 D-FW-4「FW badge 三色閾值」沒明示 PM 期待 + +**問題**:PM 列了 D-FW-4「Design 需定具體閾值」、把這個皮球丟回 Design。 +- Design §4.2 已定 3 色規則(current = 綠、older = 黃、legacy KDP1 = 紅) +- 但**沒有定義「current 之前 1 版 vs 2 版以上算什麼顏色」**——bundle 三個版本(v2.2.0 / v2.1.0 / kdp1)時、v2.1.0 是黃還是紅? +- 也沒定「壞掉的 firmware(loader mode、firmware 字串讀不到)」算什麼顏色 + +**Design 當前邏輯**(從 §4.2 推): +- 綠 = bundled current 完全相同(如 `v2.2.0`) +- 黃 = bundle 內較舊但可升(如 `v2.1.0`) +- 紅 = KDP1 系列(不論版本) + +→ 缺「壞掉 firmware」狀態的處理。 + +**建議**:PM 在 D-FW-4 補一句「Design 已定 3 色規則(綠 / 黃 / 紅)、Architect 需提供 driver 層 `FirmwareIsLegacy` / `FirmwareCanUpgrade` 判定邏輯給 Design」、或 Design 直接補一條「壞掉 firmware = 灰色 badge『狀態未知』」。 + +**阻塞性**:不阻塞 A 階段(A 只有 KL520/KL720 current + 升級、沒有 older 中間狀態)。 + +### 1.3 輕微建議(🟡) + +#### 🟡 P-LOW-1:缺「進階使用者怎麼知道要降版」user story + +**問題**:PM §4 列 3 個 US-FW、但缺一個關鍵 user story:「使用者怎麼**發現**需要降版?」 +- 情境:使用者升版後跑舊 model 出現「Error / 模型載入失敗」、怎麼從錯誤訊息推到「啊我應該降版」? +- 當前 PRD 沒明示 inference 失敗時是否暗示「可能是 FW 版本問題、考慮降版」 + +**Design 視角**:這個 user story 直接影響 Design 是否要在 Workspace inference 失敗的 error modal 加一條 hint「如果問題是 model 不相容、可以到 Settings → 韌體分頁切換版本」。當前 Design §7 失敗復原**只處理 FW 操作本身的失敗**、不處理「模型推論失敗指向 FW 問題」。 + +**建議**:PM 加 US-FW-2.5「使用者從推論錯誤推導到需要降版」、Design 後續補對應 hint UX。或標為「v2.3 未來迭代」。 + +**阻塞性**:不阻塞 v2.2、可延後到 v2.3。 + +#### 🟡 P-LOW-2:Bundle 策略對使用者的等待感 PRD 沒提 + +**問題**:PM §6 列 +7MB 安裝包衝擊、但沒列「使用者下載 / 安裝時可能多感覺到的 X 秒等待」。 +- macOS 寬頻 ~50MB/s → +7MB = +0.14s(無感) +- 一般使用者 4G hotspot ~5MB/s → +7MB = +1.4s(無感) +- 慢速 wifi 1MB/s → +7MB = +7s(有感、但仍可接受) + +**Design 視角**:這部分 Design 不需要做事(Bundle 大小是 PM/Architect 範圍)、但 PRD 缺體驗層的描述。 + +**建議**:PM §6.3 加一句「使用者層面:寬頻 +0.14s 安裝時間(無感)、慢速網路最多 +7s(仍可接受)」。 + +**阻塞性**:不阻塞、純文件 polish。 + +#### 🟡 P-LOW-3:R-FW-12「使用者看不懂版本」緩解措施不夠具體 + +**問題**:PM §8 R-FW-12「多版本管理 UX 複雜度、使用者看不懂 v2.2.0 vs v2.1.0 vs KDP1」、緩解寫「Design Agent 設計清晰版本說明文案」、太抽象。 + +**Design 視角**:Design 已具體做了: +- §3.3 每個版本有 displayName 後綴(`(current)` / `(older)` / `(legacy)`) +- §3.3 每個版本有獨立說明文字(「發布於 2024-08(與舊模型相容)」) +- §9 i18n keys 已涵蓋 + +**建議**:PM 把緩解寫具體:「Design v2.2 §3.3 + §9 i18n 已對應、含 displayName 後綴 + 版本說明文字 + KDP1 額外警告」。讓 R-FW-12 不再是 open item。 + +**阻塞性**:不阻塞、純風險追蹤 polish。 + +--- + +## 二、對 Architect TDD 的審閱 + +### 2.1 對齊良好(🟢) + +#### 🟢 A-OK-1:DisplayName 格式對齊 + +Architect TDD §4.1 `FirmwareVersion` struct: +```go +DisplayName string `json:"displayName"` // "v2.2.0 (current)" / "v2.1.0 (older)" / "KDP1 (legacy)" +``` + +Design §3.1 wireframe 顯示:「KDP2 v2.2.0 (current)」、§9.2 i18n key 對應: +- `settings.firmware.card.tag.current` → `(current)` +- `settings.firmware.card.tag.legacy` → `(legacy)` + +**對齊 100%**。但 Design 用「KDP2 v2.2.0 (current)」、Architect 用「v2.2.0 (current)」(沒前綴 KDP2)。 + +→ **小釐清**:Architect 的 `FirmwareVersion.Version` 是「v2.2.0」、Design 的 displayName 是「KDP2 v2.2.0 (current)」、兩個是「version field + displayName field 合併」嗎?建議 Architect 明示 displayName 包含 KDP 前綴:「`displayName = "{kdpFamily} {version} ({status})"`」。 + +#### 🟢 A-OK-2:WebSocket progress event schema 足夠支撐 Design UI + +Architect TDD §4.2 `FirmwareProgress` struct: +- Percent: 0-100 → 對應 Design §5.2 進度條 +- Stage: 字串列舉 → 對應 Design §5.3 階段對應表 +- Direction: `upgrade` / `downgrade` → 對應 Design §6.3 「切換韌體」vs「升級韌體」標題切換 +- Message / Error: 對應 Design §7.2 友善訊息 + +**Design 缺的:ETA(預估剩餘秒數)**。Design §5.2 範例顯示「預估剩餘 X 秒」、但 Architect schema 沒有 `EstimatedRemainingSeconds` 欄位。 + +→ **建議**:Architect 在 `FirmwareProgress` 加 optional `EstimatedRemainingSeconds int` 或 `ElapsedMs int`,Frontend 用 elapsed 自己算 ETA。 + +#### 🟢 A-OK-3:多語系策略對齊 + +Architect TDD §3.3 錯誤碼表(`FW_DEVICE_BUSY` / `FW_VERSION_NOT_FOUND` 等 6 個)→ Design §9.8 失敗訊息 8 個對應 friendly message keys。 + +**對齊 OK**、但 Architect 6 個錯誤碼 vs Design 8 個失敗類型,數量不對等(見下方 A-MISMATCH-2)。 + +### 2.2 嚴重問題(🔴) + +#### 🔴 A-MISMATCH-1:狀態機名稱不一致 + +**問題**: + +| 來源 | 狀態 / Stage 名稱 | +|------|----------------| +| Design §8 狀態機 | `idle` / `confirming` / **`preparing`** / **`loading`** / **`flashing`** / **`verifying`** / `success_toast` / `error_modal` | +| Architect TDD §4.3 stage 列舉 | `connecting` / `loading_loader` / `loading_firmware` / `verifying` / `done` / `error` | +| Architect TDD §5.1 流程 progressCh stage | `connecting` / `loading_firmware` / `verifying` / `done` | +| PM PRD AC-FW-1.2 | 「連線中 / 載入引導程式 / 寫入韌體 / 重新偵測 / 完成」(中文)| + +**衝突點**: +- Design 用 `preparing` / `loading` / `flashing` 三階段、Architect 用 `connecting` / `loading_loader` / `loading_firmware` 三階段、PM 用「連線中 / 載入引導程式 / 寫入韌體」三階段(中文) +- 全部都意指同樣的事、但名稱完全沒對齊 + +**Design 視角影響**: +- Design §9.6 i18n keys 把 stage 用 `connect` / `loader` / `upgrade` / `verify` 四個 key(在 §5.3 階段對應表) +- 但 Design §8 狀態機又用 `preparing` / `loading` / `flashing` / `verifying` +- **連 Design 自己內部都不一致**——Design §5.3 用 `connect/loader/upgrade/verify`、Design §8 用 `preparing/loading/flashing/verifying` + +**Design 自承錯誤**:這是 Design 自己沒對齊內部章節 + 沒採 Architect TDD 的命名。 + +**建議**:以 **Architect TDD §4.3 stage 列舉** 為標準(後端是 source of truth),調整: +- Design §8 狀態機:`preparing` → `connecting`、`loading` → `loading_loader`、`flashing` → `loading_firmware` +- Design §5.3 階段表的 `connect` / `loader` / `upgrade` 對齊 Architect 的 `connecting` / `loading_loader` / `loading_firmware` +- PM PRD AC-FW-1.2 不變(中文是 user-facing 文案、英文 stage code 是技術名稱) +- Design §9.6 i18n key suffix 從 `stage.connect` 改為 `stage.connecting` 等 + +**阻塞性**:**M9-3 後端 API 完成前必解**。如果 Frontend 不知道後端會推什麼 stage 字串、subscribe WebSocket 時對應不上、進度 modal 顯示「unknown stage」。 + +#### 🔴 A-MISMATCH-2:Architect 6 個錯誤碼 vs Design 8 個失敗類型不對等 + +**問題**: + +| Architect TDD §3.3 錯誤碼 | Design §7.1 失敗類型 | +|------------------------|------------------| +| `FW_DEVICE_BUSY` | — | +| `FW_VERSION_NOT_FOUND` | — | +| `FW_INVALID_DIRECTION` | — | +| `FW_NO_CONFIRM_TOKEN` | — | +| `FW_UPGRADE_FAILED` | `upgrade` / `connect` | +| `FW_UPGRADE_BRICK_RISK` | `verify` | +| — | `scan` 找不到裝置 | +| — | `loader` 寫入失敗 | +| — | Timeout(>60s) | +| — | Disconnect during op | + +**衝突點**: +- Architect 6 個是「API 層錯誤碼」(HTTP 4xx/5xx 對應) +- Design 8 個是「使用者面失敗情境」(stage 細分) +- 兩者**不在同一層**、不衝突、但對應關係沒明示 + +**Design 視角影響**: +- Design §7.2 失敗 modal 顯示「錯誤代碼:fw_upgrade_stage_loader_E102」、暗示有更細的代碼系統 +- 但 Architect 只給 6 個 API 層代碼、沒給 stage-level 代碼 +- Frontend 拿到 `FW_UPGRADE_FAILED` 後不知道對應 Design 8 種失敗類型中哪一種 + +**建議**:Architect TDD §3.3 補一段「失敗類型對應 stage」表: +``` +| 觸發 stage | API 錯誤碼 | 給 frontend 的細分 reason 欄位 | +|----------|----------|---------------------------| +| scan 失敗 | FW_UPGRADE_FAILED | reason: "scan_not_found" | +| connect 失敗 | FW_UPGRADE_FAILED | reason: "connect_failed" | +| loader 寫入失敗 | FW_UPGRADE_FAILED | reason: "loader_write_failed" | +| upgrade 中段失敗 | FW_UPGRADE_FAILED | reason: "upgrade_mid_failed" | +| verify 失敗 | FW_UPGRADE_BRICK_RISK | reason: "verify_mismatch" | +| timeout | FW_UPGRADE_FAILED | reason: "timeout" | +| disconnect | FW_UPGRADE_FAILED | reason: "disconnect_during_op" | +``` + +或在 `FirmwareProgress.Error` 字串內帶結構化資訊(Frontend 解析)。 + +**阻塞性**:M9-3 後端 API 完成前必解、不然 Frontend 拿不到細分 reason。 + +### 2.3 中等問題(🟠) + +#### 🟠 A-MID-1:Architect 沒解 graceful shutdown 拒絕 + +**問題**:Design §14.4 懸而未決第 6 點明示問: +- 降版進行中關閉 Wails 控制台 = 結束 server = 中斷降版 = 可能 brick +- Frontend / Backend 是否需要偵測「降版進行中」並擋下關閉動作? + +**Architect TDD 沒對應**: +- §8.5 「Flash() method 與 restartBridge()」段提到「FW 升降版完成後設 needsReset=true」、但**沒提**降版進行中如何拒絕 server shutdown +- §5.2 流程沒提 graceful shutdown 拒絕邏輯 +- §6.4 既有 handler 改動清單沒列「shutdown handler 加 FW 進行中檢查」 + +**Design 視角影響**: +- Design 規格已採「全螢幕 hover 攔截」(§6.3)防止 click 關 modal、但**擋不住關 Wails 控制台視窗** +- 如果 Architect 不在 server 層加保護、Design 的 UX 多層 safety net 在這個漏洞前破功 + +**建議**:Architect TDD 補一段 §8.6「降版進行中的 graceful shutdown 拒絕」: +- server 偵測 FW task 進行中、收到 SIGTERM / Wails 視窗關閉 → **延遲 shutdown**、等 FW task 完成或 60s timeout +- 同時推 WebSocket event 通知 frontend「使用者嘗試關閉、已擋下」 +- Frontend 在 Wails 控制台顯示「降版中、無法關閉」提示(Design §13.3 應補對應 UX) + +**阻塞性**:**B2 階段(M9-11/M9-12)前必解**。A 階段升級不涉及(升級失敗風險小、可中斷)、但降版必須有此保護。 + +#### 🟠 A-MID-2:Architect token 對比比率沒對應 Design §11.2 推導表 + +**問題**:Design §11.2 列了 6 個新 component token 與 Light/Dark 對比比率(4.7:1 / 5.2:1 / 4.8:1)。Design §11.2 末尾標「Architect 互審重點:請確認 Dark 模式下 legacy.fg 用黑色對紅底對比是否真的足夠」。 + +**Architect TDD 沒回應**: +- TDD §11 測試策略沒提 token 對比驗證 +- TDD §13.2 Design 互審注意沒提此項 +- ADR-001 也沒提 + +**Design 視角影響**: +- Design 的對比比率是「推算值」、需 Architect / Frontend 用 axe / Chrome DevTools contrast checker 工具實測 +- 如果實測 Dark mode 紅底黑字 < 4.5:1、Design 必須調整 token(可能改 fg 為白色、但白配紅可能更糟) +- 不解 = 違反 Design A 層 De-A2 verification(WCAG AA 對比度達標) + +**建議**:Architect TDD §11.1 加單元測試項: +``` +| firmware/tokens.test | 6 個 fw-badge token 對比 ≥ 4.5:1(light + dark)| axe-core 程式化驗證 | +``` +或 Architect 不主動驗、由 Design 在 M9-4 / M9-12 Frontend 實作時 Design QA 階段實測。 + +**阻塞性**:M9-12 Frontend 實作前必解。不解的話 Design verification 過不了。 + +#### 🟠 A-MID-3:Architect 失敗復原 §5.3 表只列 4 種、Design §7.1 列 8 種 + +**問題**: +- Architect TDD §5.3 失敗復原表:4 種(device disconnect / firmware load pre-flash / firmware load mid / verify 失敗) +- Design §7.1 失敗類型對應:8 種(scan / connect / loader / upgrade / verify / Timeout / Disconnect / 部分成功) + +**衝突**:Architect 表少了 scan 失敗、connect 失敗、loader 寫入失敗、timeout 4 種。 + +**Design 視角影響**: +- Design 已寫對應 friendly message + 復原行動的 i18n(§9.8) +- 但如果 Architect 後端沒分這 4 種、Frontend 拿到的都是 generic「FW_UPGRADE_FAILED」、Design 顯示不出 8 種不同 modal + +**建議**:與 A-MISMATCH-2 一起處理。Architect TDD §5.3 對齊 Design §7.1 8 種、或在 reason 欄位細分(見 A-MISMATCH-2 建議)。 + +**阻塞性**:M9-3 後端 API 完成前必解。 + +### 2.4 輕微建議(🟡) + +#### 🟡 A-LOW-1:Architect TDD §10 風險 R-FW-12 對齊不完整 + +**問題**:Architect TDD §10 列 R-FW-12「多版本管理 UX 複雜度」、緩解寫「預設只顯示『升級到最新』+『切換 FW 版本』、降版必須展開 + 詳細說明」。 + +**Design 視角**: +- Design 已具體做(§3.3 accordion 收合、radio list 含說明) +- Architect 寫「預設只顯示...」與 Design 不完全一致(Design 是「永遠顯示升級按鈕」、不是「預設只顯示」) + +**建議**:Architect 引用 Design 對應章節:「緩解措施由 Design v2.2 §3.3 落地(accordion + radio list + 版本說明)」。 + +**阻塞性**:不阻塞、純文件對齊。 + +--- + +## 三、對 ADR-001 的審閱 + +### 3.1 對齊良好(🟢) + +#### 🟢 ADR-OK-1:Decision / Consequences 與 Design 整體理念一致 + +ADR Decision 5 條: +1. A + B 一次做完 → Design 規格已涵蓋 A + B +2. 翻案 R5-Q9 範圍切割 → Design §1.2 範圍邊界對齊 +3. KneronPLUS Python C API → Design 不需要知道(後端細節) +4. 多版本目錄結構選項 C → Design §4.2 對齊(顯示版本不涉及目錄結構、但 Design 假設 bundled 版本有 metadata) +5. 保守 +7MB Bundle → Design 不影響 + +**對齊 OK**。 + +#### 🟢 ADR-OK-2:Consequences 負面影響第 3 條對齊 Design 多層 safety net + +ADR Consequences 列「法律 / 簽章授權待釐清」、Design 不涉及。 +列「Brick 風險未完全消除」、Design 已透過 §6 + §7 + §12 三層應對: +- §6.1 二次確認 modal + DOWNGRADE 字串 +- §6.3 全螢幕 hover 攔截 + 不可關 modal +- §7 失敗復原 8 種 friendly message +- §12 R-FW Design 對策(明示對應 brick 風險路徑) + +**對齊 OK**。 + +### 3.2 輕微建議(🟡) + +#### 🟡 ADR-LOW-1:Alternatives Considered 缺一條 Design 視角 + +**問題**:ADR 列 5 個 Alternatives,但**沒有「替代方案:先做 dev mode 降版、不面向一般使用者」**(其實 §3 「只做內部 dev mode 降版」算半個、但 ADR 是從工時 / 痛點視角討論、沒從 UX 風險視角討論)。 + +**Design 視角應補**:「替代方案 6:只做 dev mode(藏在 Settings → 進階 → 開發者選項)」的 UX trade-off: +- 優點:誤觸風險降到 0 +- 缺點:使用者明確要求面向一般使用者(H3 假設「藏在 dev mode 反而會讓真正需要降版的人找不到」) +- 否決原因:使用者 2026-05-24 拍板「面向一般使用者」+ Design 多層 safety net 評估足以擋誤觸 + +**建議**:Architect 在 ADR Alternatives §6 補上面這條 UX 視角的替代方案分析。 + +**阻塞性**:不阻塞、純 ADR 完整度。 + +--- + +## 四、總結與給 Orchestrator 的建議 + +### 4.1 對齊狀態總覽 + +| 類別 | 數量 | 狀態 | +|------|------|------| +| 🟢 對齊良好 | 6 | 不需處理 | +| 🟡 輕微建議 | 5 | 建議補、但不阻塞任何 milestone | +| 🟠 中等問題 | 4 | B 階段(M9-11 ~ M9-12)前必解 | +| 🔴 嚴重問題 | 2 | M9-3 後端 API 完成前必解 | + +### 4.2 必解項目(按優先級) + +#### 優先級 P0(M9-3 後端 API 完成前必解) + +1. **A-MISMATCH-1**:狀態機名稱不一致 + - 行動:以 Architect TDD §4.3 為準、Design 同步調整 §8 + §5.3 + §9.6 i18n key + - 工時:Design < 0.5h + - **誰來改**:Design Agent(Design 內部對齊)+ Architect 確認最終名稱 + +2. **A-MISMATCH-2**:錯誤碼 vs 失敗類型不對等 + - 行動:Architect TDD §3.3 補「失敗類型對應 stage」表 + `FirmwareProgress.Reason` 欄位 + - 工時:Architect < 0.5h + - **誰來改**:Architect Agent + +#### 優先級 P1(B2 階段 M9-11/12 前必解) + +3. **A-MID-1**:graceful shutdown 拒絕邏輯 + - 行動:Architect TDD 補 §8.6 + Design 補 Wails 控制台「降版中無法關閉」UX + - 工時:Architect 1h + Design 1h + - **誰來改**:Architect Agent(主)+ Design Agent(控制台 UX) + +4. **A-MID-2**:token 對比實測 + - 行動:M9-12 Frontend 實作時 Design QA 階段實測、不過則調整 token + - 工時:< 0.5h(用 axe 工具) + - **誰來改**:Frontend / Design(M9-12) + +5. **A-MID-3**:失敗復原表 4 vs 8 對齊 + - 行動:與 A-MISMATCH-2 一起處理 + - **誰來改**:Architect Agent + +6. **P-MID-1**:成功指標補體驗指標 + - 行動:PM 在 §7.2 補 4-5 個體驗指標 + - 工時:PM 0.5h + - **誰來改**:PM Agent(B 階段上線前) + +#### 優先級 P2(可延後 / polish) + +7. **P-MID-2**(降版用詞)/ **P-MID-3**(升級時間估算)/ **P-MID-4**(badge 閾值):PM 補 +8. **P-LOW-1 ~ P-LOW-3**:PM polish +9. **A-LOW-1**:Architect TDD R-FW-12 緩解對齊 +10. **ADR-LOW-1**:ADR Alternatives 補 Design 視角 + +### 4.3 不阻塞 M9-1 ~ M9-5 A 階段啟動 + +- A 階段(升級 only)不涉及 B2 降版、狀態機名稱對齊(A-MISMATCH-1)解決後即可進 +- A 階段不涉及 graceful shutdown 拒絕、failed type 8 分類也只在 B 階段需要(M9-11/12) +- 建議 Orchestrator **派 Architect 解 A-MISMATCH-1 + A-MISMATCH-2 之後**、即可啟動 M9-1 backend + +### 4.4 Design 本輪不改 + +依任務 prompt「不改 design、本輪只審」,Design 不主動更新 `firmware-management.md`。 +**待 Orchestrator 整合三方互審報告後、若決議 Design 需配合調整(如 A-MISMATCH-1 把狀態機名稱換成 connecting/loading_loader/loading_firmware/verifying),Orchestrator 另派 Design Agent 改檔**。 + +### 4.5 Design 自承的內部矛盾 + +- Design §5.3 階段對應表 vs §8 狀態機名稱不一致(Design 自己問題、不是 PM/Architect 引起) +- 處理 A-MISMATCH-1 時一併修 + +--- + +## 變更紀錄 + +| 日期 | 版本 | 變更 | 作者 | +|------|------|------|------| +| 2026-05-24 | v1.0 | Design 互審 PM PRD + Architect TDD + ADR-001 完成、找出 13 個對齊點(2 P0 / 4 P1 / 7 P2)| Design Agent | diff --git a/local-tool/.autoflow/03-design/v2/control-panel.md b/local-tool/.autoflow/03-design/v2/control-panel.md index 8a89cfe..ec60e58 100644 --- a/local-tool/.autoflow/03-design/v2/control-panel.md +++ b/local-tool/.autoflow/03-design/v2/control-panel.md @@ -184,7 +184,8 @@ Wails Server Control Panel(以下稱「控制台」)是 visionA-local 雙擊 | 元素 | 位置 | 文字 / 樣式 | |------|------|-----------| | 行數統計 | 左 | `Lines: {current} / 2000`,12px muted | -| 關閉提示 | 右 | `⚠ Closing this window will stop the server.`,12px muted | +| 關閉提示(預設) | 右 | `⚠ Closing this window will stop the server.`,12px muted | +| 關閉提示(韌體進行中、v2.2 新增) | 右 | `🚫 韌體更新中、關閉視窗可能造成裝置損毀`,12px `color.destructive` SemiBold(取代預設提示);對應 i18n key `control.footer.closeWarningFirmwareActive`、詳見 §6a.8 | **持久提示為什麼不彈 modal**(R5-2 解釋): - 使用者已明確決策「關閉 = 結束 server」 @@ -288,6 +289,186 @@ Banner **不可手動關閉**(避免使用者忽略問題)。只有下列條 --- +## 6a. 韌體進行中關閉攔截(v2.2 新增、對應 firmware-management §14.4 第 6 點) + +### 6a.1 為什麼需要這個 + +依 R5-2「關閉控制台 = 結束 server」,但有一個例外場景:**韌體升級 / 切換進行中**。 + +- 韌體切換 / 降版是寫 flash 的破壞性操作、中斷會造成裝置永久損毀(brick) +- 如果使用者在韌體切換進行中關掉 Wails 控制台、Wails close handler 預設會送 SIGTERM 給 server 結束 Python sidecar +- Python sidecar 正在 `update_kdp_firmware_from_files` 中段被砍 = **flash 寫一半就停 = brick** + +依 Architect TDD §8.6(v2.2 新增)、server 已實作「降版進行中拒絕 graceful shutdown」邏輯: +- server 收到 SIGTERM → 檢查 `firmware.Service.HasActiveTask()` +- 有 active task → 拒絕 shutdown、回傳 `firmwareInProgress: true` 給 Wails close handler +- 沒 active task → 正常 graceful shutdown(既有 7+1s pattern) + +控制台側需提供對應 UI 攔截關閉動作、警告使用者風險。 + +### 6a.2 觸發時機 + +下列任一情況、使用者試圖關閉 Wails 控制台時: +- 按視窗右上角 `×` 關閉鈕 +- `⌘W` / `Ctrl+W` 鍵盤快捷鍵 +- `⌘Q` / 系統選單「結束」(macOS)/ 系統匣「結束」(Windows) +- 強制最小化 + 結束程式(透過 dock / taskbar) + +→ 控制台先 query server `/api/firmware/status`(或對應 IPC method): +- 回傳 `{active: false}` → 正常走 R5-2 流程(結束 server + 關視窗) +- 回傳 `{active: true, taskInfo: {deviceName, stage, etaSeconds}}` → 觸發本節攔截 modal + +### 6a.3 攔截 Modal Wireframe + +``` +┌─ ⚠ 韌體更新進行中 ───────────────────────────────────────┐ +│ │ +│ 🚫 強制關閉可能造成裝置永久損毀 │ +│ │ +│ KL520 #1 的韌體切換正在進行中。 │ +│ 現在強制關閉應用程式會中斷韌體寫入、可能造成裝置 │ +│ 永久損毀(brick)、無法救援。 │ +│ │ +│ ┌──────────────────────────────────────────────┐ │ +│ │ 目前階段:寫入韌體(階段 3 / 4) │ │ +│ │ 預估剩餘:約 22 秒 │ │ +│ │ ████████████░░░░ 60% │ │ +│ └──────────────────────────────────────────────┘ │ +│ │ +│ ⚠ 建議「繼續等待」、約 22 秒後即可安全關閉。 │ +│ │ +│ [ 繼續等待 ] [ 強制關閉 ] │ +│ │ +└─────────────────────────────────────────────────────────────┘ +``` + +### 6a.4 元件規格 + +| 元素 | 類型 | 樣式 | +|------|------|------| +| Modal 容器 | `
` | 寬度 520px、`color.card` 背景、`color.destructive` 2px 邊框、`elevation.5` 陰影 | +| 標題 icon | `` | 24×24、`color.destructive` | +| 標題 | `

` | 18px / SemiBold / `color.destructive`、「⚠ 韌體更新進行中」 | +| 主要警語 | `` | 16px / Bold / `color.destructive`、「🚫 強制關閉可能造成裝置永久損毀」 | +| 說明段落 | `

` | 14px / regular / `color.foreground` | +| 進度資訊區 | `

` | 背景 `color.muted/30`、padding 16、圓角 `radius.md` | +| 階段文字 | `` | 13px / medium / `color.foreground` | +| 預估剩餘 | `` | 13px / medium / `color.foreground`、每秒更新(從 server WebSocket progress event 推送)| +| 進度條 | `` 或 `
` | 高 8px、`color.destructive` fill(強調危險)、`color.muted` track、圓角 `radius.full` | +| 建議文字 | `

` | 13px / regular / `color.warning`、附 ⚠ icon | +| **「繼續等待」按鈕** | Button `primary` `md` | **預設聚焦**(focus)、Enter 觸發、樣式為主要 CTA | +| **「強制關閉」按鈕** | Button `destructive ghost` `md` | 邊框 `color.destructive`、文字 `color.destructive`、背景透明(不主動誘導點擊)| + +### 6a.5 互動行為 + +**「繼續等待」**(建議路徑): +- 點擊 / Enter → 關閉 modal、保留控制台視窗 +- 控制台留在原狀態(韌體進度面板繼續顯示、log 持續更新) +- 不結束 server、不關 Wails 視窗 +- 韌體任務完成後、firmware-management §5.4 / §6.4 toast 出現、使用者可以再次嘗試關閉視窗(這次走正常 R5-2 流程) + +**「強制關閉」**(危險路徑): +- 點擊 → **不立即關閉**、跳出第二層**最終確認 modal**: + ``` + ┌─ 🚫 確定要強制關閉? ────────────────────────────────┐ + │ │ + │ 強制關閉會: │ + │ • 中斷正在進行的韌體寫入 │ + │ • 可能造成裝置永久損毀(無法救援) │ + │ • 即使重新插拔也無法復原 │ + │ │ + │ 請輸入「FORCE」確認你了解後果: │ + │ ┌──────────────────────────────────────────┐ │ + │ │ │ │ + │ └──────────────────────────────────────────┘ │ + │ (大小寫需完全相同) │ + │ │ + │ [ 返回 ] [ 確認強制關閉 ] │ + │ │ + └───────────────────────────────────────────────────────┘ + ``` +- 「FORCE」輸入框比對與 firmware-management §6.1 「DOWNGRADE」相同邏輯(嚴格 `===` 比對) +- 「確認強制關閉」按鈕在輸入 `FORCE` 前 disabled、輸入正確後變為 `destructive` 紅色 +- 點擊 → Wails close handler 跳過 server graceful shutdown 流程、直接 kill server process(傳 SIGKILL)+ 關閉視窗 + +**ESC 鍵**:等同點「繼續等待」(安全路徑)、關 modal 保留視窗 + +**外部點擊**:不可關閉(捕獲事件、抖動 modal 200ms 提示)、與 firmware-management §6.1 同設計 + +### 6a.6 視覺強度層級對比 + +| 元素 | firmware-management §6.1 降版二次確認 | 本節 §6a.3 韌體進行中關閉攔截 | +|------|------------------------------------|---------------------------| +| 場景 | 降版**開始前** | 降版**進行中** + 使用者試圖中斷 | +| 風險等級 | 中(降版本身有 brick 風險、但 < 1%)| 高(中斷正在寫 flash = 高機率 brick)| +| 確認字串 | `DOWNGRADE`(指向操作意圖)| `FORCE`(指向強制中斷)| +| Modal 邊框 | 1px | **2px**(更強烈)| +| 預設聚焦 | 「DOWNGRADE」input | **「繼續等待」按鈕**(引導安全路徑)| +| 安全 CTA | 「取消」`ghost` | **「繼續等待」`primary`**(主要 CTA、強引導)| +| 危險 CTA | 「確認切換」`destructive` filled(input 通過後)| 「強制關閉」`destructive ghost`(不主動誘導、需二次確認)| + +### 6a.7 不重複攔截 + +- 同一個關閉嘗試只跳一次 modal +- 使用者選「繼續等待」後、韌體完成前如再次嘗試關閉 → 重新跑 6a.2 流程(再次 query server status) +- 「強制關閉」確認後、modal 立即關閉、不留任何撤銷機會(已通過二次確認) + +### 6a.8 與 Footer 持久提示 §4.6 的關係 + +- §4.6 「⚠ Closing this window will stop the server.」footer 提示**仍然顯示** +- 韌體進行中時、footer 提示**改為更嚴重的紅色版本**:「🚫 韌體更新中、關閉視窗可能造成裝置損毀」 +- 對應 i18n key:`control.footer.closeWarningFirmwareActive` + +### 6a.9 i18n keys(新增) + +| Key | zh-TW | en | +|-----|-------|----| +| `control.firmwareBlock.title` | 韌體更新進行中 | Firmware update in progress | +| `control.firmwareBlock.heading` | 🚫 強制關閉可能造成裝置永久損毀 | 🚫 Force-close may permanently damage the device | +| `control.firmwareBlock.description` | {deviceName} 的韌體{operation}正在進行中。現在強制關閉應用程式會中斷韌體寫入、可能造成裝置永久損毀(brick)、無法救援。 | {operation} on {deviceName} is in progress. Force-closing the application now will interrupt the firmware write and may permanently damage (brick) the device beyond recovery. | +| `control.firmwareBlock.operation.upgrade` | 升級 | upgrade | +| `control.firmwareBlock.operation.switch` | 切換 | switch | +| `control.firmwareBlock.stage` | 目前階段:{stage}(階段 {n} / {total})| Current stage: {stage} (stage {n} / {total}) | +| `control.firmwareBlock.eta` | 預估剩餘:約 {seconds} 秒 | Estimated remaining: ~{seconds}s | +| `control.firmwareBlock.recommendation` | ⚠ 建議「繼續等待」、約 {seconds} 秒後即可安全關閉。 | ⚠ Recommended: "Continue waiting". Safe to close in about {seconds}s. | +| `control.firmwareBlock.action.continueWaiting` | 繼續等待 | Continue waiting | +| `control.firmwareBlock.action.forceClose` | 強制關閉 | Force close | +| `control.firmwareBlock.confirm.title` | 🚫 確定要強制關閉? | 🚫 Confirm force close? | +| `control.firmwareBlock.confirm.risk.interrupt` | 中斷正在進行的韌體寫入 | Interrupt the ongoing firmware write | +| `control.firmwareBlock.confirm.risk.brick` | 可能造成裝置永久損毀(無法救援) | May permanently damage the device (unrecoverable) | +| `control.firmwareBlock.confirm.risk.noRecover` | 即使重新插拔也無法復原 | Cannot be recovered even by unplugging and reconnecting | +| `control.firmwareBlock.confirm.prompt` | 請輸入「FORCE」確認你了解後果: | Type "FORCE" to confirm you understand the consequences: | +| `control.firmwareBlock.confirm.placeholder` | FORCE | FORCE | +| `control.firmwareBlock.confirm.helpText` | (大小寫需完全相同) | (case-sensitive) | +| `control.firmwareBlock.confirm.action.back` | 返回 | Back | +| `control.firmwareBlock.confirm.action.forceClose` | 確認強制關閉 | Confirm force close | +| `control.footer.closeWarningFirmwareActive` | 🚫 韌體更新中、關閉視窗可能造成裝置損毀 | 🚫 Firmware update in progress — closing window may damage device | + +合計新增 **19 個 i18n keys**(zh-TW / en 各一套)。 + +### 6a.10 無障礙考量 + +| 項目 | 設計 | +|------|------| +| Modal 結構 | `role="alertdialog"`、screen reader 主動朗讀 | +| Focus management | modal 開啟時自動 focus 「繼續等待」按鈕、focus trap | +| Tab 順序 | 「繼續等待」→「強制關閉」 | +| ESC 鍵 | 等同「繼續等待」(安全路徑)| +| 危險視覺不單靠顏色 | 標題附 ⚠ icon + 「強制關閉」按鈕附文字描述(不只是紅色) | +| Reduced motion | `prefers-reduced-motion: reduce` → modal 動畫 0ms、進度條改靜態顯示 | +| 觸控目標 | 兩個按鈕 ≥ 44×44px | +| 對比 | 紅色 destructive 對 card 背景 ≥ 4.5:1(WCAG AA、critical 信號不妥協)| + +### 6a.11 與 Architect TDD §8.6 的銜接 + +- TDD §8.6 提供 `HasActiveTask()` method 與 server graceful shutdown 拒絕邏輯 +- 控制台側透過既有 IPC(或新增一個 `/api/firmware/status` 端點)查詢 active task +- 取得 active task 資訊(`deviceName / stage / etaSeconds / direction`)後渲染本節 modal +- 「強制關閉」確認後、控制台需呼叫 server `force-shutdown` IPC method(bypass graceful shutdown)、server 收到後直接送 SIGKILL 給 Python sidecar、不等 firmware task 完成 +- 詳細 IPC 規格依 TDD §8.6 規範(Frontend M8-5 階段對接) + +--- + ## 7. 啟動行為(對應 R5-4 / R5-D3 / R5-E) ### 7.1 預設流程(v2.1 修訂) @@ -460,6 +641,12 @@ Banner **不可手動關閉**(避免使用者忽略問題)。只有下列條 | 7 | §7.1 第 5 步 | 「首次 / Settings 為 ON」 | **「每次 / Settings 為 ON」**,新增 Linux 預設 OFF 說明,流程改為 6 階段化 | R5-D3 + R5-E | | 8 | §7.1 新增 | — | 引用新檔 `v2/startup-progress.md`(R5-E 階段化啟動進度面板) | R5-E | +## 13. v2.1 → v2.2 Diff(2026-05-25) + +| # | 位置 | v2.1 | v2.2 | 來源 | +|---|------|----|----|------| +| 1 | §6a 新增整節 | — | **§6a 韌體進行中關閉攔截**(兩層 modal + 「FORCE」二次確認 + 19 個 i18n keys + 6a.8 footer 紅色變體) | firmware-management §14.4 第 6 點 + Architect TDD §8.6 + Design 三方互審吸收 | + --- -**下一步**:交 M8-5 Frontend Agent 實作(Wails 控制台 + 啟動進度面板),交 Reviewer 審查 control-panel.md + startup-progress.md 整體一致性。 +**下一步**:交 M8-5 Frontend Agent 實作(Wails 控制台 + 啟動進度面板 + 韌體進行中關閉攔截 modal),交 Reviewer 審查 control-panel.md + startup-progress.md + firmware-management.md 整體一致性。 diff --git a/local-tool/.autoflow/03-design/v2/firmware-management.md b/local-tool/.autoflow/03-design/v2/firmware-management.md new file mode 100644 index 0000000..f35d30b --- /dev/null +++ b/local-tool/.autoflow/03-design/v2/firmware-management.md @@ -0,0 +1,948 @@ +# v2.7 — Kneron Dongle FW 管理(升級 + 版本切換) + +> 本章對應 R5-Q9 翻案(FW 管理面向一般使用者)+ Architect research 30-integration-plan §M9-2/3/4 + 42-manual-downgrade-for-end-users §5。 +> 上層索引:`../design-spec-v2.md` +> 版本:**v2.2 新增** · 建立日期:2026-05-24 +> 相關: +> - 架構參考:`.autoflow/04-architecture/research-kl520-fw-management/30-integration-plan.md`、`42-manual-downgrade-for-end-users.md` +> - UI 銜接:`v2/settings-update.md`(新增分頁進這個檔的結構)、`spec/03-wireframes.md §3.3 Devices`(FW badge) + +--- + +## 1. 定位與職責 + +「韌體管理」是 Settings 內**新增的第 5 個分頁**,使用者在此: + +1. 看到每張 Kneron dongle 當前 FW 版本 + bundled 最新版的對照 +2. 升級到最新 FW(一鍵動作、KL520 KDP1→KDP2 為主要場景) +3. **切換 FW 版本(含降版)**——進階使用者操作,多層 safety guard 保護 +4. 看升級 / 切換進度、失敗復原指引 + +**這個分頁不做的事**: +- 不做 device-level inference / model 操作(那是 Workspace 的事) +- 不顯示非 Kneron 裝置 +- 不做 OTA / 線上版本更新(所有 FW 從安裝包內 bundle,R5-Q9 決策) + +**為什麼是 Settings 分頁、不是 Devices 頁主流程**: +- 降版屬於高風險操作(理論上可能 brick)、不應放在使用者點擊頻率最高的 Devices 頁 +- 升級雖然低風險,但「升級」與「切換」介面共用同一套版本選單較自然 +- 對應 architect 42 §1.2 的 trade-off 分析 + +--- + +## 2. IA 整合:Settings 分頁順序 + +依 `v2/settings-update.md §1` 的 4 分頁結構(一般 / 硬體 / 模型 / 進階)擴充為 **5 分頁**: + +| Tab | 順序 | 變更 | +|-----|------|------| +| 一般 | 1 | 不變 | +| 硬體 | 2 | 不變 | +| **韌體** | **3** | **本檔新增** | +| 模型 | 4 | 順序後移 | +| 進階 | 5 | 順序後移 | + +**為什麼放在「硬體」與「模型」之間**: +- 概念分組:硬體(裝置本身)→ 韌體(裝置韌體)→ 模型(裝置上跑的軟體資產),由低階到高階 +- 「硬體」分頁列出裝置掃描策略,使用者看完掃描設定後,自然會問「裝置韌體呢」 +- 進階分頁仍放最後(不變) + +### 2.1 分頁標籤文案 + +| Key | zh-TW | en | +|-----|-------|----| +| `settings.tabs.firmware` | 韌體 | Firmware | + +> **用詞警告**:分頁名稱**不能叫「降版」**——對一般使用者過於負面。一律稱「韌體」或「韌體管理」。「版本切換」是進階操作的中性說法。 + +--- + +## 3. 頁面結構(Wireframe) + +### 3.1 整體佈局(韌體分頁主畫面) + +預設狀態(有偵測到 2 張 dongle、其中 KL520 有可升級的版本): + +``` +┌─ Settings > 韌體 ───────────────────────────────────────────────────┐ +│ │ +│ 韌體管理 │ +│ 管理已連接 Kneron 裝置的韌體版本。 │ +│ │ +│ ───────────────────────────────────────────────────────────── │ +│ │ +│ ┌─ KL520 #1 ─────────────────────────────────────────────────┐ │ +│ │ kn_number: │ │ +│ │ ● KDP1 (legacy) 0x1A2B3C4D │ │ +│ │ 建議升級到 KDP2 v2.2.0 │ │ +│ │ │ │ +│ │ 當前版本:KDP1 │ │ +│ │ 最新版本:KDP2 v2.2.0 (建議) │ │ +│ │ │ │ +│ │ [ 升級到 KDP2 v2.2.0 ] [ 版本切換 ▾ ] │ │ +│ └────────────────────────────────────────────────────────────┘ │ +│ │ +│ ┌─ KL720 #1 ─────────────────────────────────────────────────┐ │ +│ │ kn_number: │ │ +│ │ ● KDP2 v2.2.0 (current) 0x5E6F7890 │ │ +│ │ 裝置使用最新韌體 │ │ +│ │ │ │ +│ │ 當前版本:KDP2 v2.2.0 │ │ +│ │ 最新版本:KDP2 v2.2.0 │ │ +│ │ │ │ +│ │ [ 版本切換 ▾ ] │ │ +│ └────────────────────────────────────────────────────────────┘ │ +│ │ +│ ⓘ 沒看到裝置?檢查 USB 連接後到「硬體」分頁重新掃描。 │ +│ │ +└───────────────────────────────────────────────────────────────────────┘ +``` + +**配色解讀(裝置卡片左側圓點)**: + +| 圓點顏色 | 條件 | 文字標籤 | +|---------|------|---------| +| 🔴 `color.destructive` | KDP1 / legacy FW | `KDP1 (legacy)` | +| 🟡 `color.warning` | 有可用較新版本 | `KDP2 v2.1.0 (older)` | +| 🟢 `color.success` | 已是最新 bundled 版本 | `KDP2 v2.2.0 (current)` | + +### 3.2 空狀態(無 dongle 連接) + +``` +┌─ Settings > 韌體 ───────────────────────────────────────────────────┐ +│ │ +│ 韌體管理 │ +│ │ +│ ┌──────────────────────────────────────────────┐ │ +│ │ │ │ +│ │ 🔌 │ │ +│ │ │ │ +│ │ 尚未偵測到 Kneron 裝置 │ │ +│ │ │ │ +│ │ 插上 USB 裝置後,到「硬體」分頁點擊 │ │ +│ │ 「重新掃描」便會出現在這裡。 │ │ +│ │ │ │ +│ │ [ 前往硬體分頁 ] │ │ +│ │ │ │ +│ └──────────────────────────────────────────────┘ │ +│ │ +└───────────────────────────────────────────────────────────────────────┘ +``` + +### 3.3 「版本切換」展開後(accordion 樣式、不是 dropdown) + +點 `版本切換 ▾` 後、卡片下半部展開: + +``` +┌─ KL520 #1 ─────────────────────────────────────────────────────────┐ +│ ● KDP2 v2.2.0 (current) kn_number: 0x... │ +│ 裝置使用最新韌體 │ +│ │ +│ 當前版本:KDP2 v2.2.0 │ +│ 最新版本:KDP2 v2.2.0 │ +│ │ +│ [ 版本切換 ▴ ] │ +│ ┌─────────────────────────────────────────────────────────────┐ │ +│ │ ⚠ 切換到舊版可能導致: │ │ +│ │ • 部分新版 .nef 模型無法載入 │ │ +│ │ • 推論效能與穩定性下降 │ │ +│ │ • KDP1 無法執行多模型載入 │ │ +│ │ 切換過程約需 30 秒(KL520)/ 3 分鐘(KL720),切勿拔除裝置。│ │ +│ │ │ │ +│ │ 可用版本: │ │ +│ │ ○ KDP2 v2.2.0 (current) 當前版本 │ │ +│ │ ○ KDP2 v2.1.0 發布於 2024-08(與舊模型相容) │ │ +│ │ ○ KDP1 (legacy) 僅供 third-party 工具相容測試 │ │ +│ │ │ │ +│ │ [ 取消 ] [ 切換到此版本 ] │ │ +│ └─────────────────────────────────────────────────────────────┘ │ +└─────────────────────────────────────────────────────────────────────┘ +``` + +**展開區的元件規格**: + +| 元素 | 類型 | 細節 | +|------|------|------| +| Inline warning | `

` | `color.warning/10` 背景、`color.warning` 邊框(1px)、padding 16、圓角 `radius.md` | +| ⚠ icon | inline SVG | 20×20、`color.warning` | +| 版本 radio list | `` + `