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/<chip>/{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) <noreply@anthropic.com>
218 lines
24 KiB
Markdown
218 lines
24 KiB
Markdown
# TDD v2 — visionA-local(Round-2 refactor 後)
|
||
|
||
> 作者:Architect Agent
|
||
> 版本:**v2.2**
|
||
> 日期:2026-05-24 初版 / 2026-05-25 三方互審後修(FW 管理章節吸收 PM + Design 互審 + M9-6 弱驗證新事實)
|
||
> 狀態:Draft(v2.2 由 Architect 根據使用者 2026-05-24 拍板 FW 管理方案 A + B 產出、2026-05-25 三方互審 + 使用者拍板 stage 命名 / M9 工時拆法 / AC-FW-3.5 延後 三項裁決後修;待最終使用者確認)
|
||
> 取代:`TDD.md` v1.0(2026-04-11,四輪修訂 + Plan B 補件)
|
||
> 決策來源:`progress.md` §「R5 第五輪使用者決策」+「R5-D 補充決策」+「R5-E 階段化啟動新指標」+「M9 Kneron Dongle FW 偵測 + 升降版」(2026-05-24)+「2026-05-25 三方互審後使用者裁決」
|
||
|
||
---
|
||
|
||
## 0. 版本資訊與變更摘要
|
||
|
||
### 0.0 v2.1 → v2.2 差異速覽(2026-05-24 初版 / 2026-05-25 互審後修)
|
||
|
||
| # | 變更面向 | v2.1 | v2.2 | 觸發 |
|
||
|---|---------|------|------|------|
|
||
| 1 | **FW 管理** | 沿用既有 RAM-load only(`load_firmware_from_file`)、無持久化升降版 | **新增 firmware module + ADR-001**:A 階段自動升級 KDP1 → KDP2(KL520/KL720)+ B 階段 KL630/KL730 driver 擴展 + B2 階段手動降版(面向一般使用者)+ 多版本管理 | M9 啟動(2026-05-24)|
|
||
| 2 | **R5-Q9 翻案** | 「韌體燒錄 flash → B 砍掉」維持 | **範圍切割後翻案**:升級到 Kneron 官方 KDP2 標準版本納入範圍、「使用者燒任意 model 到 flash」繼續砍 | ADR-001 |
|
||
| 3 | **新模組** | — | `server/internal/firmware/`(service / progress / versions / guards)| ADR-001 |
|
||
| 4 | **bridge.py handler** | `handle_connect` / `handle_scan` / ... | + `handle_firmware_upgrade` / `handle_firmware_downgrade` / `handle_firmware_list_versions` + `handle_connect` chip 判斷擴 KL630/KL730 + `_resolve_firmware_paths` 支援 .tar / 多版本 | M9-1 / M9-7 / M9-11 |
|
||
| 5 | **多版本目錄結構** | 扁平 `firmware/<chip>/fw_*.bin` | **`firmware/<chip>/CURRENT_VERSION` + 版本子目錄**(選項 C metadata 結構);A 階段保持扁平、B2 階段 migration | 使用者決策(2026-05-24)|
|
||
| 6 | **安裝包大小** | macOS dmg 163MB | **A 階段 +0KB / B 階段 +7MB(保守 bundle 策略)→ ~170MB** | 使用者決策 |
|
||
| 7 | **milestone 數量** | M8-1 ~ M8-10 + M8-4b(11 個) | **+M9-1 ~ M9-13**(13 個新 milestone、5 + 10.5 = **15.5 人天**)| M9 啟動 |
|
||
| 8 | **總工時估算** | ~12 人天(M8)| **+15.5 人天(M9)= 累計 ~27.5 人天** | 以上 |
|
||
| 9 | **新增檔案** | — | **`v2/firmware-management.md`** + **`adr/ADR-001-firmware-management.md`** | ADR-001 |
|
||
| 10 | **新風險** | R-v2-1 ~ R-v2-7 | + R-FW-1 ~ R-FW-13(採 PM 編號 + M9-6 新增 R-FW-13)+ R-TAR-1 ~ R-TAR-4(TDD-only、合計 17 條、詳 `v2/firmware-management.md` §10)| M9 + 2026-05-25 互審 |
|
||
| 11 | **stage 命名**(2026-05-25 互審後修) | TDD 草案用 `connecting / loading_loader / loading_firmware / verifying` | **採 Design 命名 `preparing / loading / flashing / verifying`**(使用者拍板裁決) | 三方互審 + 使用者裁決 |
|
||
| 12 | **M9-7~M9-10 工時拆法**(2026-05-25 互審後修) | TDD 自有拆法(B0 認 chip 0.5 / .tar 1.5 / KL630 inference 2.0 / KL630 升版 1.0) | **採 PM 拆法**(M9-7 1.5 / M9-8 1.0 / M9-9 1.0 / M9-10 1.5)、總和 5.0 不變 | 使用者拍板裁決 |
|
||
| 13 | **AC-FW-3.5 階段歸屬**(2026-05-25 M9-6 弱驗證新增) | 未明示 A/B 階段 | **延後至 B 階段 M9-10**(warrenchen 無 reference 實作 + 需實機驗證 KL630/KL730 適用性) | M9-6 弱驗證 |
|
||
| 14 | **wheel 三平台版本不一致**(2026-05-25 M9-6 弱驗證新增) | 未察覺 | **macOS/Linux 2.0.0 / Windows 3.1.2**、A 階段不阻塞、B 階段啟動前必須統一 | M9-6 弱驗證 |
|
||
| 15 | **graceful shutdown 拒絕**(2026-05-25 互審後修) | TDD 草案無 | **新增 §8.6**:FW task active 期間 server 延遲 shutdown + Wails force-quit modal(避免關 Wails 視窗中斷降版導致 brick) | Design A-MID-1 |
|
||
| 16 | **`FirmwareProgress` schema**(2026-05-25 互審後修) | 5 欄位 | **補 6 欄位**:Reason / ElapsedMs / EtaMs / DeviceID / BeforeVer / RawError / ErrorCode(給 Frontend ETA UI + 「複製錯誤訊息」+ i18n 對應 + 客服診斷用) | Design A-OK-2 / A-MID-3 + Architect F3 |
|
||
|
||
**未變更**(v2.1 其餘設計保持不動):Wails 視窗 = 控制台 UI、瀏覽器 tab 載業務、yt-dlp/Mock 砍除、ffmpeg LGPL 方案 B、CORS 白名單、boot-id 機制、LogBuffer 2000 行 ring buffer、state machine 5 個狀態、watchServer Error state、R5-E 6 階段啟動管線。
|
||
|
||
### 0.0a v2.0 → v2.1 差異速覽(2026-04-14 歷史保留)
|
||
|
||
| # | 變更面向 | v2.0 | v2.1 | 觸發 |
|
||
|---|---------|------|------|------|
|
||
| 1 | **AC-1.3 啟動時間** | 10 秒硬指標 | **60 秒 + 6 階段進度顯示**(20 s soft timeout / 60 s hard timeout)| R5-E1~E6 |
|
||
| 2 | **自動開瀏覽器行為** | 首次啟動開一次(`autoOpenedThisSession` flag 控制 per-session-once)| **每次 Start/Restart 成功都開**(砍 flag;R5-D3)| R5-D3 |
|
||
| 3 | **AutoOpenBrowser 預設值** | 三平台統一 true | **macOS/Windows true、Linux false**(分平台 default)| R5-D2 |
|
||
| 4 | **Server 崩潰通知** | 僅控制台 Error banner | **Error banner + OS 原生通知並存**(`notify.go` 三平台實作)| R5-D1 |
|
||
| 5 | **Shutdown grace period** | 5 s → 10 s(Architect Q4 提議)| **7 s + 1 s 顯示「停止中…」modal**(PM Q4 定案)| PM Q4 |
|
||
| 6 | **Shutdown race condition** | 靠 polling 3 次失敗(0.5-15 s 後顯示 overlay) | **WebSocket `server:shutdown-imminent` 廣播**(秒內觸發 overlay)| PM Minor 4 |
|
||
| 7 | **Restart port 處理** | 允許 fallback(3721 → 3722 …)| **強制保留舊 port**,被佔用進 Error state | Architect F-2 |
|
||
| 8 | **Preferences 持久化** | 提及 atomic write 但未定位置 | **`<dataDir>/preferences.json` + write-rename**(完整 spec)| PM §11-1 |
|
||
| 9 | **`videoIsURL` field 處置** | 「視情況保留或刪除」 | **明確刪除**(grep 證實是 dead code)| PM Minor 5 |
|
||
| 10 | **idle RAM 450 MB 目標** | 未澄清範圍 | **澄清不含瀏覽器 tab**(只計 Wails + Go server + Python)| PM §11-3 |
|
||
| 11 | **日常啟動時間估算** | 無 | **新增估算 ~3.8 s**,符合 AC-2.1 ≤ 5 s | PM Minor 2 |
|
||
| 12 | **boot-id 生成方式** | 建議 google/uuid | **用 `crypto/rand` 16 bytes → hex**(不引依賴)| Architect Q3 |
|
||
| 13 | **navigator.language fallback** | 基本 startsWith('zh') | **強化:處理 C/POSIX/空字串 + hardcoded 英文 fallback** | Architect Q5 |
|
||
| 14 | **milestone 數量** | M8-1 ~ M8-10(10 個)| **+M8-4b 階段化啟動**(11 個) | R5-E |
|
||
| 15 | **總工時估算** | ~10 人天 | **~12 人天**(R5-E +1 天、R5-D1 +0.3 天、PM Q4 +0.2 天、Minor 4 +0.3 天 + 其他 0.2 天)| 以上 |
|
||
| 16 | **新增檔案** | — | **`v2/startup-pipeline.md`**(R5-E 實作細節) | R5-E |
|
||
|
||
**未變更**(v2.0 其餘設計保持不動):Wails 視窗 = 控制台 UI、瀏覽器 tab 載業務、yt-dlp/Mock 砍除、ffmpeg LGPL 方案 B、CORS 白名單、boot-id 機制、LogBuffer 2000 行 ring buffer、state machine 5 個狀態。
|
||
|
||
### 0.1 v1 → v2 差異速覽
|
||
|
||
| 面向 | v1(2026-04-11) | v2(2026-04-14) | 觸發決策 |
|
||
|------|-----------------|-----------------|---------|
|
||
| **Wails 視窗載入內容** | Splash → `window.location.replace` 跳到 Next.js 主 UI(M7-B)| Splash 路徑完全移除,Wails 永遠停在「控制台 UI」:server 狀態 / log panel / 啟停控制 / Open in Browser | R5-1 A+B+G |
|
||
| **使用者業務 UI 承載者** | Wails WebView(M7-B 是純 HTTP,但仍在 WebView 內)| **瀏覽器 tab**(Chrome / Safari / Edge)`http://127.0.0.1:<port>/` | R5-1 |
|
||
| **yt-dlp 全套** | 保留(M6 vendor 35 MB + handler + 前端 URL tab)| **完全砍除**(vendor + handler + frontend UI + i18n + bootstrap + installer payload) | R5-7 前置;M8-1 |
|
||
| **Mock 模式** | 保留(`--mock` flag + `VISIONA_MOCK` env + UI hint + 兩份 i18n) | **完全砍除**(Go mock driver / mock camera / env var / flag / UI 元件 / i18n keys) | R5-5a |
|
||
| **ffmpeg 授權** | GPL(evermeet / BtbN / johnvansickle),`VISIONA_ALLOW_GPL_FFMPEG=1` release blocker | **LGPL 方案 B(混合)**:Win/Linux 換 BtbN LGPL;macOS 自 build decoder-only ~20 MB,binary commit 到 `vendor/ffmpeg/macos/` | R5-6 / R5-6a / R5-6b |
|
||
| **ffprobe** | 未打包 | **三平台都一起包**(ffmpeg + ffprobe) | R5-6c |
|
||
| **Tray** | 第三輪 Q-A 砍掉 | 維持砍,不復議 | R5-3 |
|
||
| **關閉視窗行為** | Q7=B 傳統式(關 = 結束 app)| 維持 Q7=B,但新增:關閉前先 `StopServer()` 優雅結束;瀏覽器 tab 偵測 server 離線後顯示全域 Offline Overlay | R5-2 |
|
||
| **Server 控制 bindings** | 只有 `GetServerStatus` / `GetServerURL` / `OpenBrowser`(隱式 start)| 補齊 `StartServer` / `StopServer` / `RestartServer` / `GetRecentLogs` / `ClearLogs` / `GetSystemInfo` 及完整 state machine | R5-1 |
|
||
| **watchServer 失敗行為** | 3 次失敗 → `reportFatal` + `os.Exit(1)`(app 一起死) | 3 次失敗 → 切 `ServerStateError`,Wails app 保留讓使用者手動 Restart 或查 log | 三方共識 #10 |
|
||
| **自動開瀏覽器** | — | 首次 server 就緒自動開一次;Settings 的 `openBrowserOnStart` 可關 | R5-4 |
|
||
| **CORS 政策** | 寬鬆(`Access-Control-Allow-Origin: <任意 Origin>`)| 嚴格 whitelist `http://127.0.0.1:*` + `http://localhost:*`;其他 Origin → 不回 ACAO header / OPTIONS 405 | 三方共識 #5 |
|
||
| **綁定 interface** | `--host 127.0.0.1` | 維持不動(不做 LAN) | R5-1 |
|
||
| **上傳影片副檔名** | `.mp4 / .avi / .mov` | `.mp4 / .avi / .mov / .mpeg / .mpg`(瀏覽器能吃 + Kneron pipeline 吃得到的交集) | 三方共識 #11 |
|
||
| **Boot-ID 機制** | 無 | 新增 `GET /api/system/boot-id`,server 啟動時產生 UUID;瀏覽器每 5 s poll,boot-id 變更 → force reload | 三方共識 #14 |
|
||
| **控制台 UI 技術選型** | — | vanilla HTML/JS/CSS,從現有 `visiona-local/frontend/` splash 改寫 | 三方共識 #7 |
|
||
| **沿用率** | — | **85-95%**(詳見 `v2/code-reuse-v2.md`) | 三方共識 #1 |
|
||
| **總工時** | — | **~10 人天**,拆成 10 個 milestone(詳見 `v2/milestone-plan.md`) | 三方共識 #1 |
|
||
|
||
### 0.2 v1 未變的決策(v2 繼續沿用)
|
||
|
||
- 三層程序模型(Wails 殼 + Go server 子行程 + Python sidecar)— D1
|
||
- Python runtime 雙策略(bundled / system / auto)— D2
|
||
- 完全放棄程式碼簽章(macOS ad-hoc、Windows 無 Authenticode、Linux 無簽章)— D3
|
||
- x86_64 only,三平台都不做 ARM — D4
|
||
- 預置模型全部打包(~73 MB),不做 auto-update、不收 telemetry — D5
|
||
- 資料目錄位置、single-instance lock、舊資料目錄遷移、IPC raise 機制全部保留
|
||
- 首次安裝 ≤ 5 分鐘、首次推論 ≤ 30 s / 回訪 15 s 等 NFR 目標不變
|
||
- Ubuntu 與 Windows 打包流程(AppImage / Inno Setup)不變
|
||
- 中英雙語(前端)機制不變,控制台 UI 使用同一份 `en-US` / `zh-TW` JSON(詳見 `v2/control-panel.md`)
|
||
|
||
---
|
||
|
||
## 1. 新架構總覽
|
||
|
||
### 1.1 三層進程模型
|
||
|
||
```
|
||
Wails 殼(桌面控制台 UI)
|
||
└─spawn─▶ Go server 子行程(Gin HTTP + WebSocket on 127.0.0.1:random_port)
|
||
├─spawn─▶ python3 kneron_bridge.py(KneronPLUS SDK,sidecar)
|
||
└─spawn─▶ ffmpeg / ffprobe(on-demand 解碼)
|
||
|
||
Wails 殼 ←── IPC / Wails bindings ── Wails 視窗內的控制台 UI(vanilla HTML/JS/CSS)
|
||
Go server ←── HTTP / WebSocket over loopback ── 瀏覽器 tab(Next.js Web UI,業務操作全在這裡)
|
||
```
|
||
|
||
**關鍵差別於 v1**:Wails 視窗**不**載入業務 UI,它是獨立的控制台(status / log / start-stop / open-in-browser / preferences)。業務 UI 在瀏覽器 tab 跑 `http://127.0.0.1:<port>/` 的 Next.js SPA。
|
||
|
||
完整 ASCII 架構圖詳見:`v2/control-panel.md` §3(控制台 UI wireframe)、`architect-analysis-round2-refactor.md` §A1(v1→v2 資料流對照)。
|
||
|
||
### 1.2 ServerController State Machine
|
||
|
||
五個狀態:`Stopped / Starting / Running / Stopping / Error`。轉換由 `ServerController.txMu + mu` 雙 mutex 保護,不可跳過中間狀態。
|
||
|
||
- **Start**:`Stopped|Error → Starting → Running`(失敗走 Error)
|
||
- **Stop**:`Running → Stopping → Stopped`
|
||
- **Restart**:`Running → Stopping → Stopped → Starting → Running`
|
||
- **watchServer 3 次失敗**:`Running → Error`(v1 是 `os.Exit`,v2 改為 Error state 讓使用者手動復原)
|
||
|
||
完整細節見 `v2/server-lifecycle.md` §5。
|
||
|
||
### 1.3 資料流摘要
|
||
|
||
| 情境 | 簡述 |
|
||
|------|------|
|
||
| **冷啟動 + R5-4 自動開瀏覽器** | Wails `OnStartup` → 常規 seed / lock / IPC → `ServerController.Start()` → spawn server + logPump × 2 → 健康檢查 → `state = Running` → 若 `openBrowserOnStart` 且本 session 首次 → `OpenInBrowser("")` |
|
||
| **Log 推送到控制台** | server stdout/stderr → `cmd.StdoutPipe/StderrPipe` → `logPump` goroutine(bufio scanner + 10 ms micro-batch)→ 同時 (1) 寫 `logs/server.{stdout,stderr}.log` + (2) append 到 `LogBuffer`(ring 2000 行)+ (3) `EventsEmit("log:append", []LogLine)` → Wails JS 訂閱 `EventsOn('log:append', ...)` → log panel 增量 render |
|
||
| **Restart 期間瀏覽器 tab 自動重連** | 使用者按 Restart → Stop → Start → server 新 boot-id → 瀏覽器 polling `/api/system/boot-id`(5 s interval,Page Visibility API)偵測到 id 變 → `window.location.reload()` |
|
||
| **關 Wails 視窗 (R5-2)** | `OnBeforeClose` return false → `OnShutdown` → watchCancel → `ServerController.Stop()`(SIGTERM → 10 s → SIGKILL)→ releaseLock → Wails quit。瀏覽器 tab 的 polling 連續 3 次失敗(15 s)→ `<ServerOfflineOverlay>` 顯示「Server 已離線」 |
|
||
|
||
詳細時序與 Go 實作見 `v2/server-lifecycle.md` §2-9;瀏覽器端實作見 `v2/web-ui-offline-overlay.md`。
|
||
|
||
---
|
||
|
||
## 2. 子檔案地圖
|
||
|
||
| # | 子檔 | 目的 | 對應 R5 決策 / M8 milestone |
|
||
|---|------|------|-----------------------------|
|
||
| 2.1 | [`v2/control-panel.md`](./v2/control-panel.md) | Wails 控制台 UI + Go App bindings + LogBuffer + log pump + 狀態機 + Preferences(R5-D2/D3)+ OS 通知觸發點 | R5-1, R5-5, R5-D1/D2/D3, R5-E;M8-4, M8-4b, M8-5 |
|
||
| 2.2 | [`v2/ffmpeg-lgpl.md`](./v2/ffmpeg-lgpl.md) | 三平台 LGPL ffmpeg vendor 策略(Makefile patch + macOS build script + 授權檔管理) | R5-6, R5-6a, R5-6b, R5-6c;M8-3 |
|
||
| 2.3 | [`v2/server-lifecycle.md`](./v2/server-lifecycle.md) | Server 生命週期細節:state machine、port 分配(F-2 強制保留)、pipe 捕捉、7+1 秒 graceful shutdown、boot-id、OS 通知(§10)、Preferences 持久化(§11) | R5-2, R5-4, R5-D1, PM Q4, F-2, PM §11-1/11-3;M8-4, M8-9 |
|
||
| 2.4 | [`v2/cors-security.md`](./v2/cors-security.md) | CORS whitelist middleware、WS origin check、資料驗證邊界 | 三方共識 #5;M8-8 |
|
||
| 2.5 | [`v2/deletions.md`](./v2/deletions.md) | yt-dlp / Mock 模式全清單(檔案 / 函式 / 行號 / i18n key / vendor / installer);v2.1 修正 `videoIsURL` / `NewVideoSourceFromURL` 明確刪除 | R5-5a, R5-7, PM Minor 5;M8-1, M8-2 |
|
||
| 2.6 | [`v2/web-ui-offline-overlay.md`](./v2/web-ui-offline-overlay.md) | 瀏覽器 tab 的 `<ServerOfflineOverlay>` 實作:polling + **WebSocket shutdown-imminent** 雙管道、重試、SSR 相容 | R5-2 三方共識 #14, PM Minor 4;M8-7 |
|
||
| 2.7 | [`v2/milestone-plan.md`](./v2/milestone-plan.md) | M8-1 ~ M8-10 + **M8-4b 階段化啟動**;總工時 ~12 人天 | 整體;M8-* |
|
||
| 2.8 | [`v2/code-reuse-v2.md`](./v2/code-reuse-v2.md) | 逐模組沿用 / 改寫 / 新寫比例表 | 整體 |
|
||
| 2.9 | [`v2/startup-pipeline.md`](./v2/startup-pipeline.md) | **v2.1 新增**:R5-E 6 階段啟動管線實作(event schema、StartupPipeline struct、watcher goroutine、60 s hard timeout / 20 s soft timeout、前端 startup-panel.js)| R5-E1~E6;M8-4b |
|
||
| 2.10 | [`v2/firmware-management.md`](./v2/firmware-management.md) | **v2.2 新增**:Kneron Dongle FW 偵測 + 升降版(A 階段 KL520/KL720 自動升級 + B 階段 KL630/KL730 driver 擴展 + B2 階段手動降版 + 多版本管理 + CURRENT_VERSION metadata + .tar firmware 處理)| ADR-001;M9-1 ~ M9-13 |
|
||
|
||
### 2.11 ADR 索引
|
||
|
||
| ADR | 主題 | Status |
|
||
|-----|------|--------|
|
||
| [`adr/ADR-001-firmware-management.md`](./adr/ADR-001-firmware-management.md) | Kneron Dongle FW 偵測 + 升降版(翻案 R5-Q9)| Accepted(2026-05-24)|
|
||
|
||
---
|
||
|
||
## 3. 風險清單(v2 更新)
|
||
|
||
繼承 v1 `risks-and-mitigations.md` 全部風險,以下為 v2 新增或升級的條目:
|
||
|
||
| # | 風險 | 等級 | 新增/升級 | 緩解 |
|
||
|---|------|------|----------|------|
|
||
| R-v2-1 | **M7-B M1 驗收漏看 Wails 視窗** 的教訓 — v2 控制台是全新 UI,重複踩同樣坑的風險 | 🟠 中 | 新增 | M8-10 驗收 checklist 強制三個檢查:(1) 雙擊 .app / .exe / .AppImage 打開後 Wails 視窗顯示的是控制台 UI(不是 splash / wizard / 白畫面);(2) 點 Open in Browser 後瀏覽器確實載入 Next.js;(3) 點 Stop 後瀏覽器 tab 能看到 Offline Overlay。每個平台都要做 |
|
||
| R-v2-2 | **macOS 自 build ffmpeg 的可重現性** — LGPL 合規稽核時必須能證明 `vendor/ffmpeg/macos/ffmpeg` 是我們在特定 configure flags 下從特定 ffmpeg commit build 出來的 | 🔴 高 | 新增 | `vendor/ffmpeg/macos/BUILD.md` 必須記錄:ffmpeg release tag(如 `n7.1`)、source tarball sha256、完整 `./configure` line、build host(macOS version + Xcode CLT version)、build date、binary sha256。未來升級 ffmpeg 時要重跑並更新 BUILD.md,不能「手改一下再傳」。同步把 configure flags 寫進 `Makefile` 的 `vendor-ffmpeg-macos-build` target(而非埋在 BUILD.md 內)讓其可 reproduce |
|
||
| R-v2-3 | **Wails EventsEmit 在高頻 stdout 下丟事件或延遲** — server boot 時 Gin / logger 一次可能噴 200+ 行;推論 frame log 若誤進 stdout 會產生秒級 30-100 行 | 🟠 中 | 新增(v1 F-4 升級)| (1) logPump 加 micro-batch:緩存 10 ms window 內的行,一次 emit 一個 `log:append` event(payload 為陣列);(2) server 推論 frame 狀態禁止用 logger.Info,改用 debug level(line-rate 測試會檢查此條);(3) 若 LogBuffer 滿 > 80% 時 logPump 降為只寫檔不 emit event(控制台看到「…(skipped N events)…」提示,使用者可 Clear Logs)。實作細節見 `v2/control-panel.md` §4 |
|
||
| R-v2-4 | **Wails 關閉視窗 → StopServer 過程中瀏覽器 tab 的 race condition** — 使用者按 × → Wails OnBeforeClose → ServerController.Stop() → SIGTERM → wait → SIGKILL → Wails 退出,**整段 ~0.5-5s 內**瀏覽器 tab 的 polling 可能看到 ECONNREFUSED 但 Overlay 還沒觸發(需連續 3 次失敗,15 s 才顯示) | 🟡 低 | 新增 | 實務上:使用者關了 Wails 視窗通常也會關瀏覽器 tab,race 不構成實際問題。若使用者真的沒關瀏覽器,15 s 後 Overlay 會出現,使用者看到「Server 已離線」訊息即可理解。不做額外優化(例:Wails 關閉前主動告知瀏覽器 — 需要 Wails → Browser 的 push channel,成本太高) |
|
||
| R-v2-5 | **macOS 自 build 的 ffmpeg 需要 codesign** — Gatekeeper 會擋未簽章的執行檔 | 🟠 中 | 新增 | (1) 在 macOS build script 最後做 `codesign --force --sign - ...`(ad-hoc sign);(2) `wails-macos` target 的 `codesign --force --deep --sign - visiona-local.app` 已覆蓋 Resources/bin 下的執行檔,沿用即可;(3) 驗收時用 `spctl --assess --verbose vendor/ffmpeg/macos/ffmpeg` 確認不會被 Gatekeeper 拒絕 |
|
||
| R-v2-6 | **boot-id polling 對瀏覽器 tab 休眠的影響** — Chrome 會把背景 tab 的 setInterval 降頻到 1 次/分鐘,可能讓使用者切回 tab 時 60 s 才偵測到 server 重啟 | 🟡 低 | 新增 | 用 Page Visibility API:tab visible → 5 s interval;tab hidden → 停 polling;tab 再次 visible → 立即 probe 一次再恢復 5 s interval。實作細節見 `v2/web-ui-offline-overlay.md` §3 |
|
||
| R-v2-7 | **砍 Mock 後空白 UI 體驗** — 使用者第一次打開沒插硬體時,Devices 頁會是空的 | 🟡 低 | 新增 | (1) Devices 頁顯示友善 empty state:「未偵測到 Kneron 裝置。請連接 KL520/KL720 後按『掃描』。」附安裝 driver 按鈕(Windows);(2) 這是 R5-5a 明示接受的結果,PRD v2 也會記錄為預期行為 |
|
||
|
||
### v2.2 新增 FW 管理相關風險(採 PM PRD §8 編號、完整清單見 `v2/firmware-management.md` §10)
|
||
|
||
| # | 風險 | 等級 | 詳見 |
|
||
|---|------|------|------|
|
||
| R-FW-1 | 升級後 device re-enumerate 不穩定 + KL520 reset bug 再現 | 中 | `v2/firmware-management.md` §10.1 |
|
||
| R-FW-2 | KneronPLUS Python wheel API 支援度 + 三平台版本不一致 | 中 | 同上 |
|
||
| R-FW-3 | bridge.py `update_kdp_firmware_from_files` macOS x86_64 / Linux x86_64 未驗證 | 中 | 同上 |
|
||
| R-FW-4 | timeout 設定不合理 | 低 | 同上 |
|
||
| R-FW-5 | Kneron firmware redistribution 法律 / 簽章授權 | **P0 release gate** | 同上、與 R5-B4 同性質 |
|
||
| R-FW-6 | 既有 `flash/` 模組命名混淆 | 低 | 同上 |
|
||
| R-FW-7 | 升級失敗 device unknown state | 中 | 同上 |
|
||
| R-FW-8 | KneronPLUS SDK 對 KL630/KL730 API 不可預測 | 🔴 高 | `v2/firmware-management.md` §10.2 |
|
||
| R-FW-9 | .tar 解包對安裝包大小衝擊 | 低 | 同上 |
|
||
| R-FW-10 | KL630/KL730 沒有 Loader mode 概念 | 中 | 同上 |
|
||
| R-FW-11 | 一般使用者誤觸降版 brick 風險 | 🔴 高 | 同上、緩解見 §11.3 + §8.6 graceful shutdown 拒絕 |
|
||
| R-FW-12 | 多版本管理 UX 複雜度 | 中 | 同上 |
|
||
| **R-FW-13**(2026-05-25 新增)| wheel 2.0.0 → 3.1.2 跨主版本升級可能 breaking change | 中 | `v2/firmware-management.md` §10.3、M9-6 弱驗證 |
|
||
| R-TAR-1 ~ R-TAR-4 | TDD-only 技術細節:.tar handling 特定風險(SDK 不接受 .tar 已確認 / build 步驟漏跑 / notarization / Python 3.12+ path filter)| 已確認 / 中 / 低 | `v2/firmware-management.md` §10.4 |
|
||
|
||
v1 已列、v2 解除的風險:
|
||
- **ffmpeg GPL release blocker(F-5, R9)** — R5-6 LGPL 方案 B 解除
|
||
- **F-1 Wails tray 在 Linux GNOME 可能壞掉** — R5-3 維持砍 tray,風險消失
|
||
- **F-3 使用者找不回 app** — R5-2 維持關閉 = 結束,風險消失
|
||
|
||
---
|
||
|
||
## 4. 審閱紀錄
|
||
|
||
| 日期 | 審閱者 | 結論 |
|
||
|------|-------|------|
|
||
| 2026-04-14 | Architect Agent | v2.0 Draft 產出 |
|
||
| 2026-04-14 | PM Agent | v2.0 互審完成(見 `reviews/pm-review-of-tdd-v2.md`)— Major × 4 / Minor × 5 |
|
||
| 2026-04-14 | Architect Agent | **v2.1** 產出:吸收 PM Major/Minor 修正 + R5-D 三條補充決策 + R5-E 階段化啟動 + Architect 自補清單(F-2 port 保留 / B-1 OS 通知 / Q1/Q3/Q5/Q7 自決)。新增 `v2/startup-pipeline.md`;總工時 ~10 → ~12 人天 |
|
||
| 2026-04-14 | PM Agent | v2.1 待再次審閱(確認 Major × 4 都已落地 + R5-D/E 理解一致)|
|
||
| 2026-04-14 | Design Agent | v2.1 待審(重點:R5-E5 啟動階段文案、7+1 秒 stopping modal 文案、startup-panel.js 視覺對齊 Design Spec v2.1)|
|
||
| 2026-04-14 | 使用者 | v2.1 待確認 |
|
||
| 2026-05-24 | Architect Agent | **v2.2** 產出:吸收使用者拍板 FW 管理方案 A + B、新增 `v2/firmware-management.md` + `adr/ADR-001-firmware-management.md`、R5-Q9 翻案(範圍切割後)。M9-1 ~ M9-13 新 milestone series、15.5 人天 |
|
||
| 2026-05-24 | PM Agent | v2.2 PM 互審完成(見 `02-prd/reviews/pm-review-of-tdd-and-design-v2.2-firmware.md`):通過 with Major × 2(MJ-A1 ADR 編號、MJ-A2 R5-Q9 行號)+ Minor × 6 |
|
||
| 2026-05-24 | Design Agent | v2.2 Design 互審完成(見 `03-design/reviews/design-review-of-prd-and-tdd-v2.2-firmware.md`):通過 with 🔴 嚴重 × 1(A-MISMATCH-1 stage 命名)+ 🟠 中等 × 3 + 🟡 輕微 × 4 |
|
||
| 2026-05-24 | Architect Agent | Architect 自互審完成(見 `04-architecture/reviews/architect-review-of-prd-and-design-v2.2-firmware.md`):自承 F1-F7 必修 + O1-O3 建議 |
|
||
| 2026-05-25 | Architect Agent | **v2.2 互審後修**:FW 管理章節吸收三方互審 + M9-6 弱驗證新事實 + 使用者三項裁決(stage 採 Design 命名 / M9 採 PM 拆法 / AC-FW-3.5 延後 B 階段 M9-10)。修改範圍:`v2/firmware-management.md`(§1.2 / §1.3 新增 / §1.4 / §1.5 新增 / §3.4 新增 / §4.2 / §4.3 / §5.1 / §5.3 / §6.1 / §7.3 / §8.6 新增 / §9 / §10 / §11.3 / §11.4 / §13 / §14)+ `adr/ADR-001-firmware-management.md`(Status update + Context R5-Q9 改描述式 + Related 補 PRD + 變更記錄 v1.1)|
|
||
| 2026-05-25 | 使用者 | v2.2 互審後修待最終確認 |
|