local-tool/: visionA-local desktop app
- M1: Wails shell + Go server + Next.js UI + Mock mode (macOS dmg ready)
- M2: i18n (zh-TW/en) + Settings 4-tab refactor
- M3: Embedded Python 3.12 runtime (python-build-standalone) + KneronPLUS wheels
- M4: Windows Inno Setup script (build on Windows runner)
- M5: Linux AppImage script + udev rule (build on Linux runner)
- M6: ffmpeg (GPL, pending legal review) + yt-dlp bundled
- Lifecycle: watchServer health check, fatal native dialog,
Wails IPC raise endpoint, stale process cleanup
.autoflow/: full PRD / Design Spec / Architecture / Testing docs
(4 rounds tri-party discussion + cross review)
.github/workflows/: macOS / Windows / Linux build CI
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
226 lines
13 KiB
Markdown
226 lines
13 KiB
Markdown
# Risks & Mitigations — visionA-local
|
||
|
||
> 重大技術風險總覽與緩解計畫。
|
||
> 優先級:P0 = 會擋住發布、P1 = 嚴重影響使用者體驗、P2 = 可接受但需監控
|
||
|
||
---
|
||
|
||
## R1:KneronPLUS Linux wheel 的 glibc 相容性
|
||
|
||
- **優先級:P0**
|
||
- **可能性:高**
|
||
- **影響:高**
|
||
- **描述:** KneronPLUS-3.1.2 Linux wheel 內的 `.so` 綁定特定 glibc 版本(manylinux2014 = glibc 2.17+)。Ubuntu 22.04 是 glibc 2.35、Ubuntu 24.04 是 glibc 2.39,理論上沒問題,但 `.so` 還依賴 libusb-1.0 的 ABI,若系統 libusb 版本太舊或太新都可能炸。
|
||
- **緩解:**
|
||
1. AppImage 內帶 `libusb-1.0.so.0`,透過 `LD_LIBRARY_PATH` 優先載入,避免依賴系統 libusb
|
||
2. M1 階段就在 Ubuntu 22.04 + 24.04 實測,若不過則降級為只支援其中一版
|
||
3. 提供明確錯誤訊息:「你的 Linux 發行版 libusb 版本不相容,請安裝 libusb-1.0.0」
|
||
- **驗證時機:** M5 Linux build
|
||
|
||
---
|
||
|
||
## R2:Windows WinUSB driver 安裝需要 UAC,使用者拒絕就無法連裝置
|
||
|
||
- **優先級:P0**
|
||
- **可能性:中**
|
||
- **影響:高**
|
||
- **描述:** Inno Setup 跑 `pnputil /add-driver` 需要 admin 權限,使用者拒絕 UAC 就裝不起來。安裝後第一次跑 app 再跳 UAC 的體驗也很差。
|
||
- **緩解:**
|
||
1. Inno Setup 設定 `PrivilegesRequired=admin`,讓使用者在啟動安裝檔時就先提權一次(比跑到一半才跳好)
|
||
2. 若使用者拒絕 → 顯示明確訊息:「driver 未安裝,app 仍可跑 Mock 模式,但無法連真實 Kneron 裝置」
|
||
3. 提供「稍後手動安裝」的備援 script(`tools/install-winusb-driver.bat`)
|
||
- **驗證時機:** M4 Windows build
|
||
|
||
---
|
||
|
||
## R3:macOS 沒有簽章,Gatekeeper 會擋
|
||
|
||
- **優先級:P1**
|
||
- **可能性:確定會發生**
|
||
- **影響:中(體驗差但可 workaround)**
|
||
- **描述:** 沒有 Developer ID notarization,首次開啟 `.app` 會跳「無法驗證開發者」的警告。需要使用者右鍵 → 開啟。
|
||
- **緩解:**
|
||
1. README 與下載頁寫清楚 workaround 步驟
|
||
2. `.dmg` 內容加入一張 `首次開啟說明.png` 圖片
|
||
3. 提供一行 terminal 命令的替代方案:`xattr -d com.apple.quarantine /Applications/visionA-local.app`
|
||
- **不做的事:** 不購買 Apple Developer 帳號(使用者決策 Q2 = C)
|
||
- **風險接受理由:** 目標使用者是內部工程師 + 技術型客戶,可接受一次性摩擦
|
||
|
||
---
|
||
|
||
## R4:python-build-standalone 可能被防毒軟體誤殺
|
||
|
||
- **優先級:P1**
|
||
- **可能性:中**
|
||
- **影響:高**
|
||
- **描述:** Windows 環境尤其常見 — 防毒軟體(特別是企業版 Symantec / Trend Micro)對內嵌 Python interpreter 有時會誤判為惡意軟體,直接刪除 `python.exe` 或整個資料夾。
|
||
- **緩解:**
|
||
1. **策略 A + B 雙保險**:bundled 被刪時自動 fallback 到 system python(使用者決策 Q1 保留 B 就是為了這個)
|
||
2. 安裝完成後驗證 `python --version` 能跑,失敗立刻 fallback
|
||
3. 提供 `--python-mode=system` 強制參數供 IT 人員 troubleshoot
|
||
4. 文件說明:若公司防毒擋住,建議白名單 `visiona-local` 安裝目錄
|
||
- **監控:** 若 M4 Windows 測試頻繁遇到此問題,考慮用 pyinstaller 替代 python-build-standalone(pyinstaller 更容易被防毒接受)
|
||
|
||
---
|
||
|
||
## R5:Windows SmartScreen 擋安裝檔下載
|
||
|
||
- **優先級:P1**
|
||
- **可能性:確定會發生**
|
||
- **影響:中**
|
||
- **描述:** 沒有 Authenticode 簽章的 installer,Windows SmartScreen 會跳「Windows 已保護您的電腦」並預設把「執行」按鈕隱藏在「更多資訊」後面。新使用者看到可能以為是病毒。
|
||
- **緩解:**
|
||
1. README 截圖示範「更多資訊 → 仍要執行」的點擊路徑
|
||
2. 下載頁顯眼標註「首次下載會看到 SmartScreen 警告,這是正常現象」
|
||
3. 盡量從固定 URL 下載(同一個 URL 被 SmartScreen 累積 reputation,久了會變成 trusted,雖然慢)
|
||
- **不做的事:** 不購買 EV Code Signing 憑證(使用者決策)
|
||
|
||
---
|
||
|
||
## R6:不做 auto-update → 後續版本推送困難
|
||
|
||
- **優先級:P2**
|
||
- **可能性:確定**
|
||
- **影響:中**
|
||
- **描述:** 使用者決策 Q6 = 不做 auto-update。這代表未來每次升級都要使用者手動下載新的 installer,而且要再次面對 Gatekeeper / SmartScreen 警告。對「內部工具」可接受,但若使用者多到一定規模,升級擴散會很慢。
|
||
- **緩解:**
|
||
1. 在 About 頁顯示當前版本 + 一個「開啟下載頁」按鈕(連到 Gitea Release),不自動檢查
|
||
2. 內部溝通管道(Slack / Email)負責通知新版本
|
||
3. 未來若需要時,可改為「手動檢查更新」(按鈕觸發,不自動),比 auto-update 輕量
|
||
- **監控:** 使用者回饋是否抱怨升級繁瑣;若變成痛點,優先做「手動檢查更新」功能
|
||
|
||
---
|
||
|
||
## R7:Apple Silicon 使用者用 Rosetta 跑 x86_64 版 → 效能 / 穩定性風險
|
||
|
||
- **優先級:P2**
|
||
- **可能性:低**(使用者決策是先只做 x86_64)
|
||
- **影響:中**
|
||
- **描述:** 使用者決策 Q4 = 三平台都只做 x86_64。對使用 Intel Mac 的使用者沒問題,但 Apple Silicon(M1/M2/M3)要走 Rosetta。風險點:
|
||
- Rosetta 翻譯 Python C extension 可能有邊界情況
|
||
- KneronPLUS `.dylib` 是 x86_64-only,必須走 Rosetta,但 pyusb / libusb 的 USB 訊號路徑在 Rosetta 下未驗證過
|
||
- 首次啟動會跳 Rosetta 安裝提示(如果使用者還沒裝)
|
||
- **緩解:**
|
||
1. 明確聲明:「本版僅支援 x86_64,Apple Silicon 需透過 Rosetta 2 執行」
|
||
2. 第一次啟動偵測 CPU 架構,若是 arm64 → 顯示 Rosetta 提示
|
||
3. 若 M1 階段測試 Rosetta 路徑不穩,評估是否加做 arm64 版本(將是 scope creep)
|
||
- **未來工作:** 若使用者多為 Apple Silicon → 第二版加 arm64 build(需要 KneronPLUS arm64 wheel,目前沒有)
|
||
|
||
---
|
||
|
||
## R8:python-build-standalone 下載 URL 可能失效
|
||
|
||
- **優先級:P2**
|
||
- **可能性:低**
|
||
- **影響:中**
|
||
- **描述:** `make vendor-sync` 依賴 astral-sh/python-build-standalone 的 GitHub Release,若他們改變命名慣例或刪除舊 release,build 會中斷。
|
||
- **緩解:**
|
||
1. `vendor/` 目錄用 git-lfs 或存到內部 artifact storage,一旦下載成功就 cache 住
|
||
2. 用固定版本號(pin `20250317`),不用 `latest`
|
||
3. 備援:fallback 到 https://www.python.org/ftp/python/ 官方 tarball(雖然不是 standalone,但至少保底)
|
||
|
||
---
|
||
|
||
## R9:預置 .nef 模型的 re-distribution 授權
|
||
|
||
- **優先級:P1**(第三輪 Q-B=B4 + 第四輪 R4-1 延續:開發階段先假設可內嵌,**使用者決定暫不主動詢問 Kneron 法務**,發佈前的 gate 維持必須 check-off,屬於 release blocker)
|
||
- **可能性:中**
|
||
- **影響:高**(若 Kneron 不允許 re-distribution,會破壞「完全離線」承諾,需改為首次啟動線上下載)
|
||
- **描述:** Kneron 預置模型是 Kneron 官方提供,但「打包在另一個產品裡再發布」的授權條款未確認。可能限制 re-distribution。
|
||
- **第三輪決策(Q-B=B4)+ 第四輪決策(R4-1):**
|
||
- **開發階段**:先假設可以重新散布,繼續把預置 `.nef` 內嵌進 payload 正常開發
|
||
- **現階段不主動詢問 Kneron**(第四輪 R4-1 使用者決定):避免過早引發授權討論影響進度
|
||
- **發佈前(M6 或首次公開 release 前)**:**必須**由 PM / 使用者向 Kneron 官方(或依循 Innovedus 既有 OEM 合約)正式確認授權條款;若屆時仍無法確認,觸發 Plan B
|
||
- **此項為 P1 release blocker**:未確認前不得對外發佈
|
||
- **Plan B 對應文件**:見 [`plan-b-online-download.md`](./plan-b-online-download.md)
|
||
- **緩解:**
|
||
1. PM Agent 在 PRD / launch-checklist 追蹤項中列為發佈前必須 check-off 的項目
|
||
2. Architect 在 `packaging.md` 的 bundle 清單中為預置模型加註「授權待 Kneron 確認」
|
||
3. 若最終不允許 → Plan B:改為首次啟動線上下載(從 Innovedus 內部 Gitea / CDN),打破「完全離線」承諾,需再與使用者確認可接受度
|
||
4. About 頁加上「模型版權:Kneron Inc.」聲明(不論授權結果都要做)
|
||
- **追蹤項(P1 release blocker):**
|
||
- [ ] PM 取得 Kneron 預置模型 re-distribution 書面授權或回信
|
||
- [ ] 若無法取得 → 觸發 Plan B,重新評估 M6 範圍
|
||
|
||
---
|
||
|
||
## R10:ffmpeg LGPL 合規要求
|
||
|
||
- **優先級:P2**
|
||
- **可能性:確定要處理**
|
||
- **影響:低(文件工作)**
|
||
- **描述:** LGPL 要求:
|
||
1. 聲明使用 ffmpeg 與版本
|
||
2. 提供 LGPL 全文
|
||
3. 提供取得 source 的方式
|
||
4. (靜態連結時)提供 relink 所需的 object files(static build 才需要)
|
||
- **緩解:**
|
||
1. 我們是動態呼叫 ffmpeg binary(不是 link),這個寬鬆很多
|
||
2. About 頁加入聲明 + 連結到 ffmpeg.org 與 LGPL 全文
|
||
3. 產品 Repo 的 `THIRD_PARTY_LICENSES.md` 列出所有第三方授權
|
||
- **驗證:** 法務 review About 頁與 license 文件(使用者決策:不優先,內部工具先發再說)
|
||
|
||
---
|
||
|
||
---
|
||
|
||
## R11:發佈通路基礎設施未確認(內部 Gitea Releases / GitHub Releases)
|
||
|
||
- **優先級:P2**(追蹤項,發佈前必須解決)
|
||
- **可能性:確定需要處理**
|
||
- **影響:中**(若無對外發佈通路,DevOps 需臨時建置或改用其他方式如 S3 + 自製下載頁)
|
||
- **描述:** PRD `release-strategy` 與 `packaging.md §7` 都假設有「內部 Gitea Release」或「GitHub Release」作為安裝檔分發通路,但 progress.md 的「未解決問題」明確列出尚未確認 Innovedus 內部有此基礎設施。
|
||
- **緩解:**
|
||
1. PM / 使用者在 M5 前確認 Innovedus 是否已有 Gitea Release 或 GitHub Release(public / private repo 皆可)的發佈通路
|
||
2. 若無 → DevOps Agent 評估改走 S3 靜態站 + 自製 `latest.json` 下載頁,或直接內部檔案伺服器
|
||
3. launch-checklist 列為發佈前必確認項
|
||
- **與 R9 的關係:** 若 R9 不允許內嵌,Plan B 的線上下載也需要這個通路,兩者共用解決方案。
|
||
|
||
---
|
||
|
||
## R12:CI runner 三平台是否齊備
|
||
|
||
- **優先級:P2**
|
||
- **可能性:確定需要處理**
|
||
- **影響:中**(若缺 runner,build 只能在開發者機器手動跑,發佈節奏與一致性差)
|
||
- **描述:** `build-pipeline.md` 假設 CI 有 macOS、Windows、Linux 三平台 runner 可分別跑 `make installer-macos/windows/linux`。實際上 Innovedus 內部 CI(GitHub Actions / Gitea Actions / Jenkins)是否已有這三種 runner 尚未確認。
|
||
- **緩解:**
|
||
1. M4(Windows)與 M5(Linux)前確認對應 runner 可用
|
||
2. 若缺 runner → 短期改為開發者本機手動跑,長期補 runner
|
||
3. macOS runner 最棘手(GitHub Actions macOS 有用量上限;自架需要實體 Mac)→ 可能要採購或借用
|
||
4. launch-checklist 列為發佈前必確認項
|
||
|
||
---
|
||
|
||
## 風險總表
|
||
|
||
| # | 風險 | P | 可能性 | 影響 | 緩解狀態 |
|
||
|---|------|---|-------|------|---------|
|
||
| R1 | Linux wheel glibc 相容性 | P0 | 高 | 高 | 有方案,需 M5 驗證 |
|
||
| R2 | Windows WinUSB UAC 被拒絕 | P0 | 中 | 高 | 有方案,需 M4 驗證 |
|
||
| R3 | macOS 無簽章 Gatekeeper | P1 | 確定 | 中 | 接受,有 workaround |
|
||
| R4 | python-build-standalone 被防毒誤殺 | P1 | 中 | 高 | 雙策略 fallback |
|
||
| R5 | Windows SmartScreen 警告 | P1 | 確定 | 中 | 接受,文件說明 |
|
||
| R6 | 不做 auto-update 擴散慢 | P2 | 確定 | 中 | 接受 |
|
||
| R7 | Apple Silicon 走 Rosetta | P2 | 低 | 中 | 接受 |
|
||
| R8 | pbs 下載失敗 | P2 | 低 | 中 | vendor cache + pin 版本 |
|
||
| R9 | .nef 授權(Kneron re-distribution) | **P1** | 中 | 高 | **Release blocker**:開發階段內嵌,R4-1 決定暫不主動問 Kneron,發佈前 gate 維持 |
|
||
| R10 | ffmpeg LGPL 合規 | P2 | 確定 | 低 | 文件工作 |
|
||
| R11 | 發佈通路基礎設施未確認 | P2 | 確定 | 中 | 追蹤項,M5 前確認 |
|
||
| R12 | CI runner 三平台是否齊備 | P2 | 確定 | 中 | 追蹤項,M4/M5 前確認 |
|
||
|
||
## 新發現的風險(相對 round 1)
|
||
|
||
相較於第一輪分析(`architect-analysis-round1.md`),第二輪多出以下幾個風險:
|
||
|
||
- **R4**(python-build-standalone 被防毒誤殺):這是因為決策 Q1 = A 內嵌 Python 後才浮現,round 1 當時還傾向用系統 Python 所以沒這個問題
|
||
- **R8**(pbs 下載 URL 失效):同上,由新的內嵌方案引入
|
||
- **R7**(Apple Silicon 走 Rosetta):round 1 建議做 Universal Binary,Q4 決策改為只做 x86_64 後,Rosetta 路徑未經驗證變成風險點
|
||
|
||
**已解決(相對 round 1):**
|
||
- ~~R1 Apple Developer 憑證~~ → 決策 Q2 接受無簽章
|
||
- ~~R2 Windows EV Cert~~ → 決策 Q2 接受 SmartScreen
|
||
- ~~R3 KneronPLUS macOS arm64~~ → 決策 Q4 只做 x86_64,不用管 arm64 wheel
|
||
- ~~R4 離線 wheel vs 線上下載~~ → 決策 Q1 A 完全離線
|
||
- ~~R5 預置模型精簡~~ → 決策 Q5 全打包
|