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>
13 KiB
13 KiB
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 版本太舊或太新都可能炸。 - 緩解:
- AppImage 內帶
libusb-1.0.so.0,透過LD_LIBRARY_PATH優先載入,避免依賴系統 libusb - M1 階段就在 Ubuntu 22.04 + 24.04 實測,若不過則降級為只支援其中一版
- 提供明確錯誤訊息:「你的 Linux 發行版 libusb 版本不相容,請安裝 libusb-1.0.0」
- AppImage 內帶
- 驗證時機: M5 Linux build
R2:Windows WinUSB driver 安裝需要 UAC,使用者拒絕就無法連裝置
- 優先級:P0
- 可能性:中
- 影響:高
- 描述: Inno Setup 跑
pnputil /add-driver需要 admin 權限,使用者拒絕 UAC 就裝不起來。安裝後第一次跑 app 再跳 UAC 的體驗也很差。 - 緩解:
- Inno Setup 設定
PrivilegesRequired=admin,讓使用者在啟動安裝檔時就先提權一次(比跑到一半才跳好) - 若使用者拒絕 → 顯示明確訊息:「driver 未安裝,app 仍可跑 Mock 模式,但無法連真實 Kneron 裝置」
- 提供「稍後手動安裝」的備援 script(
tools/install-winusb-driver.bat)
- Inno Setup 設定
- 驗證時機: M4 Windows build
R3:macOS 沒有簽章,Gatekeeper 會擋
- 優先級:P1
- 可能性:確定會發生
- 影響:中(體驗差但可 workaround)
- 描述: 沒有 Developer ID notarization,首次開啟
.app會跳「無法驗證開發者」的警告。需要使用者右鍵 → 開啟。 - 緩解:
- README 與下載頁寫清楚 workaround 步驟
.dmg內容加入一張首次開啟說明.png圖片- 提供一行 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或整個資料夾。 - 緩解:
- 策略 A + B 雙保險:bundled 被刪時自動 fallback 到 system python(使用者決策 Q1 保留 B 就是為了這個)
- 安裝完成後驗證
python --version能跑,失敗立刻 fallback - 提供
--python-mode=system強制參數供 IT 人員 troubleshoot - 文件說明:若公司防毒擋住,建議白名單
visiona-local安裝目錄
- 監控: 若 M4 Windows 測試頻繁遇到此問題,考慮用 pyinstaller 替代 python-build-standalone(pyinstaller 更容易被防毒接受)
R5:Windows SmartScreen 擋安裝檔下載
- 優先級:P1
- 可能性:確定會發生
- 影響:中
- 描述: 沒有 Authenticode 簽章的 installer,Windows SmartScreen 會跳「Windows 已保護您的電腦」並預設把「執行」按鈕隱藏在「更多資訊」後面。新使用者看到可能以為是病毒。
- 緩解:
- README 截圖示範「更多資訊 → 仍要執行」的點擊路徑
- 下載頁顯眼標註「首次下載會看到 SmartScreen 警告,這是正常現象」
- 盡量從固定 URL 下載(同一個 URL 被 SmartScreen 累積 reputation,久了會變成 trusted,雖然慢)
- 不做的事: 不購買 EV Code Signing 憑證(使用者決策)
R6:不做 auto-update → 後續版本推送困難
- 優先級:P2
- 可能性:確定
- 影響:中
- 描述: 使用者決策 Q6 = 不做 auto-update。這代表未來每次升級都要使用者手動下載新的 installer,而且要再次面對 Gatekeeper / SmartScreen 警告。對「內部工具」可接受,但若使用者多到一定規模,升級擴散會很慢。
- 緩解:
- 在 About 頁顯示當前版本 + 一個「開啟下載頁」按鈕(連到 Gitea Release),不自動檢查
- 內部溝通管道(Slack / Email)負責通知新版本
- 未來若需要時,可改為「手動檢查更新」(按鈕觸發,不自動),比 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 安裝提示(如果使用者還沒裝)
- 緩解:
- 明確聲明:「本版僅支援 x86_64,Apple Silicon 需透過 Rosetta 2 執行」
- 第一次啟動偵測 CPU 架構,若是 arm64 → 顯示 Rosetta 提示
- 若 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 會中斷。 - 緩解:
vendor/目錄用 git-lfs 或存到內部 artifact storage,一旦下載成功就 cache 住- 用固定版本號(pin
20250317),不用latest - 備援: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
- 開發階段:先假設可以重新散布,繼續把預置
- 緩解:
- PM Agent 在 PRD / launch-checklist 追蹤項中列為發佈前必須 check-off 的項目
- Architect 在
packaging.md的 bundle 清單中為預置模型加註「授權待 Kneron 確認」 - 若最終不允許 → Plan B:改為首次啟動線上下載(從 Innovedus 內部 Gitea / CDN),打破「完全離線」承諾,需再與使用者確認可接受度
- About 頁加上「模型版權:Kneron Inc.」聲明(不論授權結果都要做)
- 追蹤項(P1 release blocker):
- PM 取得 Kneron 預置模型 re-distribution 書面授權或回信
- 若無法取得 → 觸發 Plan B,重新評估 M6 範圍
R10:ffmpeg LGPL 合規要求
- 優先級:P2
- 可能性:確定要處理
- 影響:低(文件工作)
- 描述: LGPL 要求:
- 聲明使用 ffmpeg 與版本
- 提供 LGPL 全文
- 提供取得 source 的方式
- (靜態連結時)提供 relink 所需的 object files(static build 才需要)
- 緩解:
- 我們是動態呼叫 ffmpeg binary(不是 link),這個寬鬆很多
- About 頁加入聲明 + 連結到 ffmpeg.org 與 LGPL 全文
- 產品 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 內部有此基礎設施。 - 緩解:
- PM / 使用者在 M5 前確認 Innovedus 是否已有 Gitea Release 或 GitHub Release(public / private repo 皆可)的發佈通路
- 若無 → DevOps Agent 評估改走 S3 靜態站 + 自製
latest.json下載頁,或直接內部檔案伺服器 - 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 尚未確認。 - 緩解:
- M4(Windows)與 M5(Linux)前確認對應 runner 可用
- 若缺 runner → 短期改為開發者本機手動跑,長期補 runner
- macOS runner 最棘手(GitHub Actions macOS 有用量上限;自架需要實體 Mac)→ 可能要採購或借用
- 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 接受 SmartScreenR3 KneronPLUS macOS arm64→ 決策 Q4 只做 x86_64,不用管 arm64 wheelR4 離線 wheel vs 線上下載→ 決策 Q1 A 完全離線R5 預置模型精簡→ 決策 Q5 全打包