A 階段第四個 milestone、完整 Frontend FW UI(badge / modal / 8 種 reason 復原)+ backend WS hot-fix(補對稱於 flash 的 firmware WS endpoint)。 Frontend(13 修改 / 7 新檔): - 新 firmware/ component group (badge / upgrade-button / upgrade-dialog 4-phase / progress-view / error-view 8-reason / index) - Zustand store (firmware-store.ts) + WS hook (use-firmware-progress.ts) 對齊既有 useFlashProgress pattern - DeviceCard 整合 FirmwareBadge + FirmwareUpgradeButton - i18n: settings.firmware.* namespace (對齊 Design Spec §9 SoT) + devices.card.fwBadge.* (zh-TW + en, 57 leaf keys × 2 lang = 114 strings) - toast.ts ToastOptions interface (duration param) - types/device.ts: FW 衍生欄位 + FirmwareStage/Reason/ProgressEvent/ActiveTask types Backend WS hot-fix (3 檔): - ws/firmware_ws.go (50 行、純對稱 flash_ws.go) - ws/firmware_ws_test.go (165 行、2 smoke tests: broadcast + room isolation) - router.go: GET /ws/devices/:id/firmware-progress 關鍵設計: - R-FW-11 緩解: upgrading phase modal 不可關 (onInteractOutside/onEscapeKeyDown preventDefault + 隱藏 X) - 多裝置隔離 defense in depth: store handleEvent activeDeviceId mismatch 直接 return - 8 種 reason → 4 種 UX (recoverable/destructive/brick 警告/contactSupport) - ContactSupport mailto handler (RFC 6068 + encodeURIComponent) Reviewer 兩輪審查: - Round 1: 0 Critical / 3 Major / 8 Minor / 5 Suggestion - Round 2: 0 Critical / 0 Major / 0 Minor / 2 Suggestion(接受方案 A、不需 frontend 第 3 輪) - MJ1 i18n namespace 採方案 A (settings.firmware.*)、Design SoT 優先、Reviewer 同意 測試: - pnpm test --run: 60 tests pass (32 firmware: 22 store + 10 badge + 新 9 error-view + 19 既有) - npx tsc --noEmit: 0 error - pnpm build: production build 成功 - go test ./internal/api/ws/... -race: 1.964s 全綠 - pnpm lint firmware/: 0 hit (17 既有 lint 問題不屬 M9-4、follow-up) 未做(範圍外): - Settings 韌體面板 (M9-12 B 階段) - 手動降版 UI (M9-12) - 版本切換 dropdown (B 階段) - Wails 控制台 force-quit modal (M9-4.5) A 階段 MVP 後端 + 前端開發全部完成、剩 M9-4.5 (SIGTERM + Wails OnBeforeClose) + M9-5 (三平台實機驗證) Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
83 KiB
專案進度 — visionA-local
目的:全新專案(從 edge-ai-platform 衍生的 local 版本)
當前階段:🟡 M9 — Kneron Dongle FW 偵測 + 升降版(L 級新功能、翻案 R5-Q9)
當前狀態:✅ Architect 研究 plan 完成、使用者拍板方案 A + B、待補 PRD v2.2 / Design Spec v2.2 / TDD v2.2 + ADR-009 → 之後 KL630/KL730 driver 擴展需另一份研究
最後更新:2026-05-24
2026-05-24 M9 啟動:Kneron Dongle FW 偵測 + 升降版
背景
使用者要在 visionA-local 加 Kneron Dongle FW 偵測 + 升降版功能。同事 warrenchen 在 gitea/warrenchen/web_academy_prototype/local_service_win 有可參考實作。同事是雲端網頁 + 本地服務雙進程版本、我們是單進程 Wails、不需要那 7 組 RPC / 自訂 URL scheme / 引導下載安裝本地代理。
重要決策(2026-05-24)
- 採方案 A + B(一次做完)+ L 級正規流程
- 方案 A(MVP,5 人天):KL520 + KL720 自動升級 KDP1 → KDP2、安裝包 +0KB
- 方案 B(追加,5-7 人天):手動降版 + KL630 + KL730、安裝包 +5MB、需先擴 driver
- 合計 ~10-12 人天
- 翻案 R5-Q9(progress.md L776 第二輪 Q9「韌體燒錄 flash → B 砍掉」):
- 當時砍的是「使用者按按鈕燒 model 到 device flash」、不是 FW 升降版
- 現在要做的是「升級到 Kneron 官方 KDP2 標準版本」、範圍縮小避開大部分原始擔憂
- 將透過 ADR-009-firmware-management 留下決策痕跡
- 跨平台用 KneronPLUS C API、不用 DFUT.exe(Windows-only / 30MB 依賴)
- flash/ vs firmware/ 模組分離:既有
flash/保持「load model 到 device RAM」原意、新建firmware/模組做升降版
Architect 研究產出(已完成 2026-05-24)
.autoflow/04-architecture/research-kl520-fw-management/00-research-summary.md(184 行、執行摘要).autoflow/04-architecture/research-kl520-fw-management/10-warrenchen-impl-analysis.md(259 行、warrenchen 實作分析).autoflow/04-architecture/research-kl520-fw-management/20-our-current-state.md(292 行、現有 code 盤點).autoflow/04-architecture/research-kl520-fw-management/30-integration-plan.md(662 行、MVP milestone + 風險清單)
關鍵技術發現
- visionA-local 既有 code 已有 70% 的 FW 偵測 + RAM-load 邏輯(bridge.py 已
kp.core.load_firmware_from_file) - 缺的是「持久化升降版」(既有是 RAM-load、要呼叫
kp_update_kdp_firmware_from_files寫 flash) - KL520/KL720 firmware 已 bundle 在
server/scripts/firmware/{KL520,KL720}/(~360KB) - KL630/KL730 driver 現況沒處理 product_id(0x0630 / 0x0730)+ firmware 是 .tar 不是 .bin、要先擴 driver 才能加 FW 支援
與既有架構的銜接點
- watchServer Error state:FW 升級失敗是 device 層、不應觸發 server Error
- KL520 reset bug(2026-04-21):升級成功後 device re-enumerate、要等 5-8 秒 + 主動 rescan
- R5-E 60s 啟動上限:FW 升級是使用者主動觸發、不在啟動 pipeline、無關(但升級本身 30-180s、UI 要 progress bar)
B 階段研究完成(2026-05-24 第二輪)
- ✅
.autoflow/04-architecture/research-kl520-fw-management/40-b-phase-kl630-kl730-extension.md(703 行) - ✅
.autoflow/04-architecture/research-kl520-fw-management/41-tar-firmware-handling.md(458 行) - ✅
.autoflow/04-architecture/research-kl520-fw-management/42-manual-downgrade-for-end-users.md(551 行)
B 階段新發現
- warrenchen 沒做 KL630/KL730 FW 升降版、只 bundle firmware tar、沒實作流程
- KL630/KL730 連線流程跟 KL520/KL720 不同、bridge.py
handle_connect()對它們 fall-through 到 KL520(會連不上) - .tar firmware 處理是 unknown 區、3 候選策略待 SDK 驗證
- 工時更新:A 5 + B 10.5 = 15.5 人天(原估 11-12、增加因「面向一般使用者」UX safety net + 多版本管理 + SDK 驗證)
B 階段 4 個使用者決策(2026-05-24)
- 多版本目錄結構:選 C — CURRENT_VERSION metadata(
firmware/<chip>/{v2.2.0,v2.1.0,kdp1}/+CURRENT_VERSION單行檔;架構乾淨、跨平台無 symlink 風險) - Bundle 策略:保守策略 +7MB(KL520 提供 kdp1 + v2.1.0 兩個降版、KL720/KL630/KL730 current + 1 個舊版如有)
- Kneron firmware redistribution 授權:先不管授權(風險:發佈前可能要重新評估、與 R5-B4 同性質問題)
- M9-6 SDK 驗證時機:跟 A 階段平行(不拖完整進度)
翻案 R5-Q9 確認
- 透過 ADR-009-firmware-management 留紀錄
- 把「使用者按按鈕燒任意 model 到 device flash」與「升級到 Kneron 官方 KDP2」範圍切開
- 詳見
00-research-summary.md§1 R5-Q9 翻案分析
安裝包大小衝擊(最終)
- A 階段:+0KB(KL520/KL720 firmware 已 bundle)
- B 階段:+7MB(保守策略 = KL520 +2 版降版 + KL720/KL630/KL730 各 +1 舊版)
- macOS dmg 預估從 163MB → ~170MB
下一步(L 級正規流程、三線平行)
Track 1(A 階段文件補寫):
- PM PRD v2.2 完成(2026-05-24)
.autoflow/02-prd/features/feature-firmware-management.md(523 行、14 章節).autoflow/02-prd/PRD-v2.md升 v2.2(492 行、淨減 8、留 8 行 buffer / 未破 500)- Q9 翻案紀錄(§2)+ 範圍切割(§3)+ 4 個 US-FW user story(§4)+ user research 假設(§5)+ 成功指標含 Brick < 0.1%(§7)+ R-FW-1
12 風險(§8)+ Q-FW-17 未解問題(§9)+ M9-1~13 工時表(§10) - 14 個待互審項:D-FW-1
6 給 Design / A-FW-16 給 Architect / O-FW-1~2 給 Orchestrator - 最大不確定性 A-FW-4 / O-FW-2:KneronPLUS Python wheel 對 KL630/KL730 update API 支援度 → 取決於 M9-6 SDK 驗證、可能讓 AC-FW-3.5「降級為 FW 偵測 only」生效
- PRD-v2.md 已卡上限:v2.3+ 任何補丁都會破 500、PM 建議考慮 PRD 模組化拆分
- PM 修改完成(2026-05-25)
- PRD-v2.md:492 → 495 行(buffer 5、未破 500)
- feature-firmware-management.md:523 → 599 行(+76)
- MJ-A1 ADR 編號 ADR-009→ADR-001 全 grep replace 完成
- MJ-A2 R5-Q9 行號改描述式引用
- MJ-D1 降版 framing 對齊 Design 中性立場
- MJ-D2 US-FW-2 拆 US-FW-2a 一般使用者 / US-FW-2b 進階使用者
- A-MID-1 graceful shutdown → 補 AC-FW-1.9
- P-MID-1 體驗指標 → 補 §7.2.1 體驗指標 5 條(完成率 / 中途放棄率 / 重試率 / NPS / 客服問詢率)
- 新增 R-FW-13(wheel 三平台版本不一致 P1)
- M9-0 補 35 分鐘強驗證 + AC-FW-3.5 延後 B 階段 + M9-8 策略 Y 註明
- 屬於 Architect 的 Minor 全標「⏳ Architect 處理中」、不擅自修 TDD
- 給 Orchestrator 追蹤:O-FW-1(R5-B4 release blocker 合併追蹤)+ O-FW-2(M9-10 啟動時評估 AC-FW-3.5 生效條件)
- Architect TDD v2.2 + ADR-001 完成(2026-05-24)
.autoflow/04-architecture/v2/firmware-management.md(466 行、< 500 不拆檔).autoflow/04-architecture/adr/ADR-001-firmware-management.md(152 行、Accepted).autoflow/04-architecture/TDD-v2.md版本 v2.1 → v2.2、§0.0 差異速覽 + §2.10 子檔索引 + §2.11 ADR 索引 + §3 R-FW 風險引用 + §4 審閱紀錄- ADR-001 編號正確(adr/ 目錄掃描空、不撞號)
- 工時量化 15.5 人天(M9-1=1.0 / M9-2=1.0 / M9-3=0.5 / M9-4=1.5 / M9-5=1.0 / M9-6=1.0 / M9-7=0.5 / M9-8=1.5 / M9-9=2.0 / M9-10=1.0 / M9-11=1.5 / M9-12=2.0 / M9-13=1.0)
- 5 個給 PM 互審注意(Q9 範圍切割 / R5-B4 授權 P0 懸念 / 工時 +安裝包對下載率 / Error 15 回歸 AC / B2 一般使用者面板)
- 5 個給 Design 互審注意(DOWNGRADE 嚴格輸入框 / 6 錯誤碼 + 4 失敗類型友善文案 / Stage 6 個 × 2 方向 i18n / R-FW-11/12 UI safety net 全落地 / 版本字串對齊 CURRENT_VERSION)
- Architect 修改完成(2026-05-25)
v2/firmware-management.md:604 → 823 行(+219)adr/ADR-001-firmware-management.md:210 → 218 行(+8)TDD-v2.md索引:202 → 217 行(+15)- 7 必修 F1-F7 全完成(stage 命名 / 對應表 / FirmwareProgress 補欄位 / graceful shutdown §8.6 / 工時採 PM 拆法 / R-FW 編號採 PM / bridge.py handler 同步)
- 3 建議 O1-O3 全完成(KL530/KL830 不做 / R-TAR TDD-only / 升級期間關 Wails 視窗測試)
- MJ-A1 ADR-009→ADR-001:Architect 管轄 4 檔已修
- MJ-A2 R5-Q9 行號改描述式
- §3.4 完整 stage→錯誤碼→Reason→i18n 對應表
- §8.6 graceful shutdown 拒絕設計(server lock + Wails force-quit modal)+ 工時併 M9-11
- Design v2.2 完成(2026-05-24)→
.autoflow/03-design/v2/firmware-management.md(920 行、明示不拆理由)+design-spec-v2.md索引更新- 5 分頁結構(Settings 新增「韌體」插在硬體與模型之間)
- Devices 頁 card FW badge(綠/黃/紅)+ deep-link icon
- 二次確認 modal(輸入「DOWNGRADE」嚴格比對)
- 52 個 i18n keys(中英雙語)
- 6 個新 design tokens
- R-FW-11.5 / R-FW-11.6 自提風險(Design 視角)
- 6 個給 Architect 互審待確認(token 對比 / DOWNGRADE 字串 / 8 種失敗 stage / 狀態機名稱 / 降版中拒 graceful shutdown / 分頁順序)
- 4 個給 PM 互審待確認(Q9 翻案章節 / 進階使用者 user story / 用語一致性 / 成功指標 Brick < 0.1%)
- 三方互審(進行中)
- PM 互審報告完成(2026-05-24)→
.autoflow/02-prd/reviews/pm-review-of-tdd-and-design-v2.2-firmware.md(~250 行)- 結論:通過 with Major 修正
- 3 Major:MJ-A1 ADR 編號(PRD 寫 ADR-009 vs 實檔 ADR-001 不一致)/ MJ-A2 R5-Q9 行號 cross-check(L776 vs L854)/ MJ-D1+D2「降版」用詞 framing + US-FW-2 拆分涵蓋進階使用者
- 11 Minor(Architect 6 + Design 5)
- 修改工作量:Architect 0.2 + PM 0.55 + Design 0.1 人天
- Design 互審報告完成(2026-05-24)→
.autoflow/03-design/reviews/design-review-of-prd-and-tdd-v2.2-firmware.md- 結論:🟢 整體一致、可進 M9-12 Frontend、但有 2 個 P0 必解
- P0 A-MISMATCH-1 狀態機名稱不一致:Design 用 preparing/loading/flashing/verifying、Architect 用 connecting/loading_loader/loading_firmware/verifying、PM 中文版又不同 → 建議以 Architect 為準、Design 自己也要修內部不一致
- P0 A-MISMATCH-2 錯誤碼 vs 失敗類型不對等:Architect 6 個 API 錯誤碼 vs Design 8 種 UI 失敗情境、缺對應表、Frontend 無法 map → Architect 補對應表 + FirmwareProgress.Reason 欄位
- 4 P1(graceful shutdown 拒絕 / token 對比實測 / 失敗復原表 4vs8 / PM 缺體驗指標)+ 7 P2
- 對齊良好 6 項
- 不阻塞 A 階段 M9-1~M9-5(A 階段沒降版 + 沒 graceful shutdown)
- Design 修改完成(2026-05-25)
v2/firmware-management.md:916 → 948 行(+32、未拆檔、門檻調 800→1000)v2/control-panel.md:466 → 652 行(+186,新增 §6a 整節 graceful shutdown 攔截 modal + FORCE 二次確認 + 19 i18n keys)- P0 A-MISMATCH-1 stage 命名統一 preparing/loading/flashing/verifying(§5.3 / §7.1 / §8 / §9.6 / §9.8 全部對齊)
- P0 A-MISMATCH-2 失敗對應表:§7.1 加 backend stage 欄 + Reason 細分(scan_not_found/connect_failed/loader_write_failed/upgrade_mid_failed/verify_mismatch/timeout/disconnect_during_op)
- P1 A-MID-1 graceful shutdown UI 在 control-panel.md §6a 落地
- P1 A-MID-2 token 對比實測責任歸 M9-12 Frontend
- i18n 從 52 → 51 keys(細分修改)
- Discord 殘留查證不存在(PM 互審那輪可能誤判)
- 與 Architect 銜接點:Reason enum 字串需 Architect 在 TDD §3.4 照抄 +
HasActiveTask()IPC 規格需提供 deviceName/stage/etaSeconds/direction 欄位
- Architect 互審報告完成(2026-05-24)→
.autoflow/04-architecture/reviews/architect-review-of-prd-and-design-v2.2-firmware.md(438 行)- 結論:PM/Design 技術上都可實現、整體對齊度高、無架構衝突
- 對 PM:通過 + 2 Major(M9 工時拆法 / R-FW 編號)+ 4 Minor
- 對 Design:通過 + 2 Major(stage 命名 / graceful shutdown)+ 4 Minor
- Architect 自承下輪需修 7 必修 + 3 建議項(F1-F7 + O1-O3)
- ⚠️ 與 Design 互審讓步衝突:
- Design 說「stage 命名以 Architect 為準」
- Architect 說「stage 命名以 Design 為準」
- 需 Orchestrator/使用者裁決
- M9-6 強驗證完成(2026-05-25)→
.autoflow/04-architecture/research-kl520-fw-management/56-m9-6-strong-validation-result.md(246 行)- 🔴 推翻 1:macOS/Linux 2.0.0 wheel 沒有 KL630/KL730 enum(確認)+ KL730 product_id 是 0x732 不是 0x730(前兩輪研究假設值錯)
- 🔴 推翻 2:KL630/KL730 .tar 不是 fw_scpu.bin + fw_ncpu.bin、是 embedded Linux rootfs(ELF + 80+ .so / 5.8MB+32MB / 完全不同代設計)→ 弱驗證的「策略 Y 唯一可行」結論不成立、需全新策略 X(spike 在 M9-8)
- 附帶發現:KneronPLUS 3.1.2 Python wrapper 沒有
update_kdp_firmware_from_files、warrenchen 是 ctypes 直接打 .so C symbol、繞過 Python wrapper → TDD 必須明示「走 ctypes」 - A 階段不阻塞:KL520+KL720 跨 2.0.0/3.1.2 wheel 一致、AC-FW-3.5 確定延後 B 階段
- B 階段工時 +2-3 人天:原估「build script 解壓即可」、實際需 spike 找 KL630/KL730 全新 SDK 機制
- M9-6 弱驗證完成(2026-05-24)→
.autoflow/04-architecture/research-kl520-fw-management/55-m9-6-weak-validation-result.md- 關鍵發現 1:KneronPLUS 3.1.2 enum 確認 KL520/KL720/KL720_LEGACY/KL630/KL730/KL830 全存在
- 關鍵發現 2:
update_kdp_firmware_from_files(dg, scpu, ncpu, auto_reboot)簽名完整取得 - 關鍵發現 3:
KDP_MAGIC_CONNECTION_PASS = 0x1FF55B4F(繞 KDP1 firmware check) - 關鍵發現 4:策略 Z(餵 .tar 給 SDK)確定不可行 — 必須走策略 Y(解壓後傳 .bin path)
- 🔴 關鍵發現 5(重大):wheel 三平台版本不一致!macOS/Linux = 2.0.0、Windows = 3.1.2 — A 階段 KL630/KL730 升降版必先升 macOS/Linux wheel
- 關鍵發現 6:warrenchen 對 KL630/KL730 升降版完全沒實作、無 reference code、是 gap 不是 SDK 限制
- 10 unknown 解 ~50%、足以開始 A 階段
- A 階段啟動前唯一阻塞:派 backend agent 跑 35 分鐘強驗證(A-2 + C-1)
- 建議 AC-FW-3.5(KL630/KL730 升降版)延後到 B 階段 M9-10
- PM 互審報告完成(2026-05-24)→
Track 2(B 階段技術前置、與 Track 1 平行):
- Architect M9-6 SDK 驗證 plan 完成(2026-05-24)→
.autoflow/04-architecture/research-kl520-fw-management/50-m9-6-sdk-validation.md(~500 行)- 10 個 unknown 分 3 類(A SDK API / B 連線行為 / C tar 內容)
- 強驗證 2 人天 / 弱驗證 1 人天
- 4 個 R-VAL 風險(硬體 / wheel / 假設錯 / 環境)
- 建議 A 階段 M9-3 或 M9-4 完成後啟動實機驗證、避開 bridge.py 改檔衝突
- 派工前要確認:KL630/KL730 dongle 硬體狀態(有/多久能拿到/沒有)→ 決定走強驗證或弱驗證
Track 3(開發):
- M9-1 bridge.py firmware_upgrade handler 完成(2026-05-25)
server/scripts/kneron_bridge.py:1207 → 1973 行(+767)server/scripts/test_kneron_bridge_firmware.py:622 行(新檔、27 unit tests 0.069s 全綠)server/scripts/firmware/KL520/fw_loader.bin:90112 bytes(從 warrenchen 複製、MD5aef7cca17bc023abbd6152c46c18e774一致)server/scripts/firmware/{KL520,KL720}/VERSION:v2.2.0- 完全對齊 TDD §6.1:stage 採 Design 命名 / 8 種 reason enum 7 覆蓋(disconnect_during_op 留 M9-5 實機)/ ctypes 走法 1:1 warrenchen / progress event schema 含 percent/stage/message/elapsed_ms/eta_ms/extra
- 唯一邊界決定:KL720 legacy 無 fw_loader.bin、走 flash-based 模式(不過 loading stage、直接
kp_update_kdp_firmware_from_files(scpu, ncpu))、保守 + 向前相容 - 既有功能無 regress:scan/connect/disconnect/reset/load_model/inference 一行沒改
- 待 M9-2/3/5 解決:Go driver stderr 解析 / Service mutex / HasActiveTask / disconnect_during_op 實機 / 三平台 ctypes 實機驗證
- M9-1 Reviewer 第 1 輪審查完成(2026-05-25)→
.autoflow/05-implementation/review/m9-1-bridge-firmware-upgrade-review.md- 結論:0 Critical / 3 Major / 4 Minor / 4 Suggestion
- 建議阻擋 M9-2 直到 M1+M2 修完(0.2 人天)
- Major M1:
_FwError/_FwTimeoutError/_fw_handle_failureclass 宣告在 handler 之後(讀者邏輯流動問題、5 分鐘可修) - Major M2:
needs_loader控制流隱式、需抽should_run_loader_stagebool(M9-2 Go driver 易誤判 stage 完成度) - Major M3:
_fw_classify_legacysubstring match 對 firmware 字串覆蓋不足 - 4 Minor + 4 Suggestion 可留 M9-1 修改一起處理或 M9-5 follow-up
- TDD §6.1 規格對齊度 98%
- 不升級給 Security Auditor(5 軸 security 重點 4 過、1 Minor)
- M9-1 Backend 第 2 輪修改完成(2026-05-25)
kneron_bridge.py:1973 → 2058 行(+85)test_kneron_bridge_firmware.py:622 → 840 行(+218、27 → 36 tests、0.076s、0 regression)- 3 Major M1+M2+M3 全修
- 4 Minor m1+m2+m3+m4 全修
- s3 firmware 字串覆蓋擴展(legacy_exact set + KDP3+ forward-compat)
- s4 補 4 個 test case
- 留 follow-up:s1 handler ~330 行抽 phase helper / s2 rescan exponential backoff
- M9-1 Reviewer 第 2 輪審查完成(2026-05-25)→
.autoflow/05-implementation/review/m9-1-bridge-firmware-upgrade-review-round2.md- 結論:通過 with 1 Minor + 1 Suggestion、解除 M9-2 阻擋
- 第 1 輪 8 項 issue 修了 8 項(M1/M2/M3/m1/m2/m3/m4-prod/s4 全到位)
- 第 2 輪新發現:0 Critical / 0 Major / 1 Minor m5(test 檔
_firmware_upgrade_start_ts死碼)/ 1 Suggestion s5(test 註解) - 不需 backend 第 3 輪、m5+s5 可在 M9-2 期間順手清
- TDD §6.1 對齊度維持 98%、M3 forward-compat 對未來 KDP3+ device brick 風險顯著改善
- 既有 6 handler 零改動驗證通過
- M9-1 整體完成(2026-05-25)→ 通過 with Suggestions、可進 M9-2
- M9-2 Go driver + firmware service 完成(2026-05-25)
server/internal/firmware/types.go:新檔 123 行(FirmwareVersion / FirmwareProgress / ActiveTaskInfo / UpgradeDriver interface / 8 reason const)server/internal/firmware/progress.go:新檔 141 行(仿 flash pattern 的 Tracker)server/internal/firmware/service.go:新檔 346 行(核心 service)server/internal/firmware/service_test.go:新檔 517 行、11 testsserver/internal/driver/kneron/kl720_driver.go:697 → 948 行(+251、UpgradeFirmware method + helpers + stderr route)server/internal/driver/kneron/kl720_driver_test.go:新檔 177 行、8 teststest_kneron_bridge_firmware.py:清 M9-1 留下的 m5 + s5(+9/-2)- 測試結果:Go 25/25 pass(1.8s+1.0s)、全 server
go test ./...全 pass 無 regression、race-clean、Python 36/36 pass - TDD 對齊:§4.2 / §4.3 / §5.1 / §6 / §6.1 / §8.6 / §3.4 全到位
- 2 個 Deviation(合理):
guards.go/versions.go未建(B2 階段 M9-11 才需要、A 階段 service.go 已內嵌最簡實作)- SIGTERM handler 串接 main.go 留 M9-3(避免大改既有 shutdown flow)
- 給 M9-3 的銜接 API:
taskID, progressCh, err := svc.UpgradeFirmware(ctx, deviceID, chip)+ WebSocket roomfirmware:<deviceID>廣播 +HasActiveTask()/GetActiveTaskInfo()給 control panel - M9-1 follow-up 順手清:m5 + s5 全做
- M9-2 Reviewer 第 1 輪完成(2026-05-25)→
.autoflow/05-implementation/review/m9-2-go-driver-firmware-service-review.md- 結論:0 Critical / 2 Major / 5 Minor / 5 Suggestion、不阻擋 M9-3、不升 security
- Major 1:sendCommand goroutine 持 d.mu 整段升級 60-200s + timeout deadlock(kl720_driver.go:860-866+875)
- Major 2:fwProgressCh close-channel race(kl720_driver.go:758-797 + service.go:197-203、production 跑萬次會踩 panic)
- 5 Minor(brickRiskReasons / 補測試 / needsReset 早退 / 註解順序 / fwMu atomic 缺口)
- 5 Suggestion(done event 去重 / multi-device 測試 / ListBundledVersions Stat / struct 共用 / cancel field godoc)
- M9-1 follow-up(m5 + s5)正面驗證通過
- 建議 backend 第 2 輪修 Major 1+2(production race、修起來成本不高)
- M9-2 Backend 第 2 輪修改完成(2026-05-25)
kl720_driver.go:948 → 1054(+106、新 sendCommandForUpgrade 60 行 snapshot pattern + fwUpgradeMu)kl720_driver_test.go:177 → 360(+183、3 新 test:InfoNotBlockedDuringUpgrade / CtxCancelReleasesBridge / StderrEventAfterCtxCancel 100 round stress)service.go:346 → 373(+27)service_test.go:517 → 676(+159、2 新 test + ListBundledVersions 改 tempdir)progress.go:141 → 147(+6、Task.cancel godoc)- Major 1 修法:方案 B 變體(fwUpgradeMu 獨立鎖 +
sendCommandForUpgrade()snapshot stdin/stdout pattern、避開 d.mu field-level race) - Major 2 修法:方案 A 變體(tryRouteFirmwareEvent 持 fwMu 整段、配合 driver defer setFirmwareProgressCh(nil) 提供 happen-before 保證)
- Minor 1-5 + Suggestion 1/2/3/5 全修
- 留 follow-up:Suggestion 4(bridgeFirmwareEvent / FirmwareProgress struct 合併、可在 M9-3 wire WS 時順手做)
- 測試:go test ./... -race -count=1 全綠(28s)/ Python 36 tests + 22 subtests 全綠(0.31s)/ go vet / build 0 output / 0 regression
- M9-2 Reviewer 第 2 輪通過(2026-05-25)→
.autoflow/05-implementation/review/m9-2-go-driver-firmware-service-review-round2.md- 結論:0 Critical / 0 Major / 2 Minor / 2 Suggestion、不阻擋 M9-3、不需 backend 第 3 輪
- 第 1 輪 11/12 issue 全修到位(Suggestion 4 backend 明示留 follow-up)
- Major 1 snapshot pattern 驗證:stdin/stdout snapshot 後 release d.mu、ctx.Done 路徑自然 return、無 panic 無 leak、lock 順序單向(fwUpgradeMu → d.mu)無反序 deadlock
- Major 2 happen-before 驗證:fwMu 保證 inflight tryRouteFirmwareEvent 必定 either「set nil 前完成 send」or「set nil 後讀到 ch==nil return false」、絕無 send on closed channel panic
- Minor R-1(attemptedUpgrade 位置)驗證後撤回降為 Suggestion R-3
- Minor R-2(Disconnect/stopPython 沒主動清 fwProgressCh、純防禦性、目前無 bug)
- CI 建議:M9-3 PR 加
go test -race -count=3提升 race detection 強度
- M9-2 整體完成(2026-05-25)→ 通過、可進 M9-3
- M9-3 API handler + WebSocket progress 完成(2026-05-25)
server/internal/api/handlers/firmware_handler.go:新檔 404 行server/internal/api/handlers/firmware_handler_test.go:新檔 632 行、26 subtestsserver/internal/api/handlers/device_handler.go:197 → 238(+41、4 個 firmware 衍生欄位)server/internal/api/router.go:236 → 259(+23、routes)server/main.go:381 → 391(+10、wire firmware service + handler)- 4 endpoint 全到位:
GET /api/devices加 firmwareVer/firmwareIsLegacy/firmwareCanUpgrade/bundledFirmwareVersionPOST /api/devices/:id/firmware/upgrade→ 202 +{taskId}GET /api/firmware/active-tasks- WS room
firmware:<deviceID>broadcast schema 對齊 §4.2
- 錯誤碼:DEVICE_NOT_FOUND / FW_UNSUPPORTED_CHIP / FW_DEVICE_BUSY / FW_UPGRADE_FAILED / FW_UPGRADE_BRICK_RISK
- go test ./... -race 全綠
- SIGTERM main.go 整合留 M9-4.5(合理、與 Wails OnBeforeClose 一起做、會新增 M9-4.5 milestone)
- M9-3 Reviewer 第 1 輪完成(2026-05-25)→
.autoflow/05-implementation/review/m9-3-api-handler-ws-review.md- 結論:0 Critical / 1 Major / 3 Minor / 5 Suggestion、不阻擋 M9-4、不升 security、需 backend 第 2 輪
- Major 1:JSON schema 雙鍵衝突(
firmwareVersionfrom DeviceInfo +firmwareVerfrom FirmwareDerivedFields 兩鍵同存) - 起因:派任務時引用 TDD §3.1 line 131 寫了 firmwareVer、但既有 device JSON 已有 firmwareVersion → 我(Orchestrator)給的規格有錯
- 修法:deviceWithFirmware 顯式定義 3 個欄位(移除重複 firmwareVer)+ TDD line 131 改回 firmwareVersion + 補 enrichDevices JSON 輸出測試
- 3 Minor(ctx.Background 註解 / bundledVersion cache 永不重試 / test device manager error format 沒鎖)
- 5 Suggestion(bridge.py classify 一致性 / forward goroutine done sleep grace / unknown error log / firmwareFeatureEnabled / goroutine leak 直接驗證)
- 正面評價:3 層 interface + DeviceManagerAdapter 解循環依賴乾淨、26 subtests async-aware 不 flaky、tasks nil→[] 體貼 frontend
- Architect TDD §3.1 修正完成(2026-05-25)→ firmware-management.md line 131
firmwareVer→firmwareVersion、grep 確認無殘留 - M9-3 Backend 第 2 輪修改完成(2026-05-25)
device_handler.go:238 → 244(+50/-2)firmware_handler.go:404 → 465(+61)firmware_handler_test.go:632 → 938(+306、新增 5 個 test func / 19 個 test points)- Major 1 修法:刪
FirmwareDerivedFields.FirmwareVer欄位、frontend 直接讀 DeviceInfo 既有firmwareVersion鍵;補 schema test grep 確認firmwareVer0 命中 - Minor M-2/3/4 全修(ctx.Background godoc / bundledVersion 只 cache success / test 用 JSON 結構斷言不檢查 error message string)
- Suggestion 1/3/5 全修(isLegacyFirmware 對齊 bridge.py + parity 真值表 / unknown error log / goroutine leak 直接驗證 cleanupCalls==1)
- 留 follow-up:S-2(forward done sleep grace、分析無 race 不修)/ S-4(firmwareFeatureEnabled flag、YAGNI)
- 測試:go test ./... -race -count=1 全綠(handlers 2.489s / api 3.522s / ws 4.623s / device 1.931s / firmware 2.695s / driver/kneron 5.583s / model 5.022s)
- go vet / build 0 output
- M9-3 Reviewer 第 2 輪通過(2026-05-25)→
.autoflow/05-implementation/review/m9-3-api-handler-ws-review-round2.md- 結論:0 Critical / 0 Major / 0 Minor / 3 極小 Suggestion、不阻擋 M9-4、不需 backend 第 3 輪、不升 security
- 第 1 輪 9 issue 處理:8 修 + 1 合理 defer(S-4 YAGNI)
- Major 1 修法完全到位、3 個 test 鎖定 regression
- S-1/S-2/S-4 backend 不修分析確認合理
- 3 個極小 Suggestion 全部 backend 不需處理(純評估)
- M9-3 整體完成(2026-05-25)→ 通過、可進 M9-4
- M9-4.5 server SIGTERM + Wails OnBeforeClose(新增、併 M9-4 或之後做)
- M9-4 Frontend FW badge + 升級 modal 完成(2026-05-25)
- 12 新增 + 4 修改 = 16 檔、3052 行
- 新增 i18n:firmware.* 52 keys + devices.card.fwBadge.* 5 keys = 57 leaf × 2 lang = 114 翻譯字串
- 新元件:FirmwareBadge / FirmwareUpgradeButton / FirmwareUpgradeDialog(4 phase)/ FirmwareProgressView / FirmwareErrorView(8 種 reason)
- Zustand store + WS hook(pattern 對齊 useFlashProgress)+ 整合 DeviceCard
- R-FW-11 緩解:upgrading phase modal 不可關(onInteractOutside / onEscapeKeyDown preventDefault + 隱藏 X)
- 多裝置隔離(defense in depth):firmware-store activeDeviceId mismatch 直接 return
- 測試:51 tests pass(32 新 + 19 既有)、pnpm build 4.6s 全綠、tsc --noEmit 0 error、lint 對我的檔案 0 hit
- 發現問題:backend 缺
/ws/devices/:id/firmware-progressendpoint(M9-3 只實作 broadcast、沒實作 WS handler)→ 需 hot-fix - 未做(範圍外):Settings 韌體面板 / 降版 UI / 版本切換 dropdown → M9-12
- M9-4-hotfix Backend WS endpoint 完成(2026-05-25)
server/internal/api/ws/firmware_ws.go:新檔 50 行(對稱 flash_ws.go、純改名)server/internal/api/ws/firmware_ws_test.go:新檔 165 行、2 smoke tests(broadcast / room isolation)server/internal/api/router.go:+2(route 註冊)- go test -race 全綠(1.964s)/ go vet / build 0 output
- M9-4 Reviewer 第 1 輪完成(2026-05-25)→
.autoflow/05-implementation/review/m9-4-frontend-firmware-review.md- 結論:0 Critical / 3 Major / 8 Minor / 5 Suggestion、不阻擋 M9-5、不升 security
- MJ1:i18n namespace 與 Design §9 偏離(structure mismatch)→ Frontend 第 2 輪
- MJ2:FirmwareErrorView
title硬編碼中文 → 一行修 i18n - MJ3:backend smoke test schema 用
phase/firmware:progress、應為stage/firmware_progress→ 併 M9-5 順手修 - 8 Minor(toast 停留 / Dark mode token TODO / test fallback / 漏 RTL test / disabled ContactSupport UX 等)
- 5 Suggestion(modal 寬度 480px / selector 優化 / 抽 helper 等)
- 需 Frontend 第 2 輪(MJ1+MJ2+部分 Minor)、不需 Backend 第 2 輪(MJ3 併 M9-5)
- M9-4 Frontend 第 2 輪修改完成(2026-05-25)
- MJ1 採方案 A(namespace →
settings.firmware.*、對齊 Design §9 source of truth)— 而非 Reviewer 偏好的方案 B(flat)- 理由:Design §9 是三方對齊後 SoT、Frontend 不該自行翻案;B 階段 M9-12 會加更多 settings.firmware 下 keys、現在不對齊將造成分散維護
- 若 Reviewer 堅持 B、需 Orchestrator 派 Design 先改 spec
- MJ2 一行修 + 順手把 ContactSupport disabled→enabled + mailto handler
- 8 Minor 全處理(含 M5 補 FirmwareErrorView 9 個 RTL tests)
- 2 Suggestion 修(S1 480px / S5 抽 formatTechnicalInfo helper)
- 3 Suggestion 留 follow-up(S2/S3/S4 屬 Testing 範圍或 acceptable trade-off)
- 行數變化:13 檔案、+243/-1
- 測試:60 tests pass(+9 FirmwareErrorView)/ tsc 0 error / pnpm build 成功 / lint firmware/ 0 hit(17 既有 lint 問題不屬 M9-4 範圍、follow-up)
- 0 regression
- MJ1 採方案 A(namespace →
- M9-4 Reviewer 第 2 輪通過(2026-05-25)→
.autoflow/05-implementation/review/m9-4-frontend-firmware-review-round2.md- 結論:0 Critical / 0 Major / 0 Minor / 2 Suggestion、接受方案 A、不阻擋 M9-5、不需 frontend 第 3 輪、不升 security
- MJ1 方案 A 接受:Frontend pushback 邏輯紮實(Design SoT 優先 + B 階段必然要落 settings.firmware + cost 低)、Reviewer 同意
- 12 項應修全到位、3 留 follow-up(合理)、1 不適用(MJ3 屬 backend/testing)
- 2 nice-to-have Suggestion(mailto 地址抽常數 / handleCopy 補 test)— 不阻擋
- ContactSupport mailto 安全性驗證通過(RFC 6068 + encodeURIComponent)
- M9-4 整體完成(2026-05-25)→ 通過、可進 M9-5
- M9-5 三平台實機驗證
- M9-6 ~ M9-13(B 階段擴展)
2026-04-21 推論 bbox 標註不顯示 + KL520 Error 15(S 級 bug fix)
症狀
Mac 版 app 上傳單張圖推論,畫面上完全沒有 bbox 標註。
根因(兩層獨立問題,疊加讓「bbox 完全不見」)
Layer 1(前端 canvas 尺寸):
camera-inference-view.tsxrenderedSize初始值硬寫{w:640, h:480}- ResizeObserver 理應在
<img>load 後 fire 更新成實際顯示尺寸(例如 516×640 直式圖 → CSS 640×794),但實測沒 fire 或 fire 時機不對 - 結果 overlay canvas 永遠用 640×480 畫,和 img 實際 DOM box 對不上 → 就算有 detection,bbox 位置會嚴重偏位甚至跑出 canvas
Layer 2(後端推論 Error 15):
kp.inference.generic_image_inference_send回ApiKPException Error 15 SEND_DATA_TOO_LARGE- 試過:image 尺寸(516×640 / 640×794 / 640×640 pad)、傳 numpy vs bytes、明確傳 width/height — 全部都炸
- Python bridge 直接測試(
/tmp/test_bridge.py)做完整connect → reset → reconnect → load_model → inference→ 11 個 detection 正常回傳 - 對比 Go driver 實際路徑:
connect → load_model → inference跳過了 reset
兇手:commit ddf0eb8(2026-04-16)
KL520 首次 connect 跳過不必要的 device reset — 當時為解 Windows 60s HTTP timeout(Loader mode connect 不穩定 + firmware load 總耗 64s)而加的優化,讓 KL520 首次 connect 不再 restartBridge。
副作用:KL520 雖然是 USB Boot / RAM-based 裝置,理論上每次 connect 是 clean state,但實測若 session 間 firmware 殘留(fw=KDP2 Comp/U),直接 load_model + inference 100% 炸 Error 15。只有走完整 reset → 退回 Loader → 重新載 firmware 到 Comp/U 流程,才能拿到能正常 inference 的 session。
修法
前端(camera-feed.tsx + camera-inference-view.tsx):
<img>加onLoadhandler,圖片 decode 完立刻用getBoundingClientRect回報尺寸(最可靠時機)- ResizeObserver effect 進來先檢查
img.complete && naturalWidth > 0,是就立刻 report(cover HMR / cached image) - effect 依賴加
streamUrl / batchImageUrl,換圖會重觀察 renderedSize初始值改null,overlay 改為isStreaming && renderedSize才 render(避免首次用預設值畫錯)- setState callback 用 prev 比對,同尺寸不觸發 render
後端(server/internal/driver/kneron/kl720_driver.go):
- 移除
ddf0eb8的「KL520 跳過 reset」特例,讓 KL520 和 KL720 都走needsReset=true → restartBridge() - 註解記錄 trade-off:KL520 connect 時間從 ~2s 變 ~15-20s(macOS),Windows 可能 60s+
- 同步調整
server/internal/api/handlers/device_handler.goconnect timeout:60s → 120s,為 Windows worst-case(~65s)留 buffer
Python bridge(server/scripts/kneron_bridge.py):
- 無實質改動(試過 host-side letterbox、numpy→bytes、明確傳 w/h 全部無效 → 還原回原版,確認問題在 Go driver 的 reset 流程)
- 只加了 debug log(
Inference: sending.../Inference: parse done, detections=N/Inference EXCEPTION with traceback),追 bug 時用,commit 前會保留(低成本、高價值)
驗證(function 層)
/tmp/test_bridge.py 直接測試 bridge JSON-RPC:
[5/5] inference (real 516x640) keys: ['taskType', 'timestamp', 'latencyMs', 'detections', 'classifications']
✅ inference OK — detections=11 classifications=0 latency=308.3ms
- person 0.705 bbox=(x=0.427, y=0.526, w=0.089, h=0.070)
- person 0.701 bbox=(x=0.360, y=0.438, w=0.227, h=0.246)
- tie 0.639 bbox=(x=0.351, y=0.573, w=0.011, h=0.107)
...
✅ 1920x1080 OK — detections=0
✅ 512x512 OK — detections=0
=== ALL TESTS PASSED ===
三種尺寸(516×640 直式 / 1920×1080 横式 / 512×512 正方)全通過。
已驗證(2026-04-21)
- Mac UI Comp/U 殘留路徑:reset 後推論 11 個 bbox 正確
- Mac UI Loader cold-boot 路徑(拔插 USB):skip reset 後推論 11 個 bbox 正確
- Windows 實測首次 connect:106s 成功(< 120s timeout),推論正確
後續優化:Windows connect 106s → 預期 ~40s(方案 C)
Windows 實測發現即使 timeout 120s 夠用,使用者要等 106s 體感太久。拆解 瓶頸發現走了兩次 firmware load(第一次 connect 進來 Loader → load fw → Comp/U ~35s / reset → 回 Loader / reconnect → load fw → Comp/U ~30s), reset 流程中第二次 firmware load 是白做工。
條件性 reset(方案 C):
kneron_bridge.py connect回報fresh_firmware_loadedflagTrue:本次 connect 內部剛做過 firmware load(原本是 Loader)False:進來就是 Comp/U(上次 session 殘留,需要 reset 清乾淨)
kl720_driver.go判 flag 決定要不要做 restartBridge reset
驗證兩條路徑都 OK(2026-04-21):
- Loader cold-boot → skip reset → 推論 11 bbox ✓
- Comp/U 殘留 → 做 reset → 推論 11 bbox ✓
預期效益:
- Windows cold-boot(最常見):106s → ~40s(省 65s)
- Mac 跨 session(最常見):~15-20s 不變
- 極少數情境(Windows 但 device 未斷電):維持走完整 reset 流程
待驗證
- Linux 實測
- Windows 實測方案 C 效益(預期 cold-boot 降到 ~40s)
前端 debug log 去留
camera-overlay.tsx 的 console.log('[bbox-debug] ...') 驗證完成後可清可留。保留成本低,對未來 debug 有幫助。
2026-04-20 macOS 掃不到 Kneron 裝置(S 級 bug fix)
症狀:Mac 版 app 啟動後,前端顯示沒有裝置(實際 KL520 透過 USB 連上)。
根因(兩層):
- 主要:
PythonModeAuto預設「先 system 後 bundled」,系統 python3 通常沒裝 KneronPLUS wheel →import kp失敗 → bridge 降級 pyusb → pyusb 找不到 libusb → scan 空。 - 次要(潛在):macOS hardened runtime 會剝掉
DYLD_LIBRARY_PATH;若未來 bundle 架構變動 dyld 找不到 libkplus 的相依 libusb,會再踩坑。
修法:
visiona-local/app.goPythonModeAuto語意翻轉 → 先 bundled(已預裝 kp wheel),失敗才 fallback system。理由:local-tool 整包內嵌 Python + wheels,系統 python 不會裝 kp,不該優先。server/scripts/kneron_bridge.py在import kp前新增_preload_kneron_dylibs_macos()— 用ctypes.CDLL絕對路徑預載 wheel 內kp/lib/libusb-1.0.0.dylib+libkplus.dylib,避開 DYLD 被 hardened runtime 砍的風險。Windows/Linux 分支不動。- 同步 bridge 到 payload/{darwin,linux,windows}/scripts/ + build bundle。
驗證:
go build兩個 module 都通過- bridge script 直跑:
{"cmd":"scan"}→ 回傳 KL520 裝置kn_number 0xB906162C - 待 rebuild wails app 後實測(需要
make wails-macos)
2026-04-20 macOS DMG 美化(S 級)
需求:Mac 端也要有 installer(類比 Windows .exe)。走方案 C(create-dmg 美化 DMG + 背景圖 + Applications 捷徑)。
實作:
- 新增
installer/macos/{make-dmg-background.py, background.png, background@2x.png, README.md}- 動態生成 640×400 深色背景(對齊 Wails 控制台 splash 配色
#111827→#0B0F19+#38BDF8accent) - 含 1x + 2x Retina 版本
- 動態生成 640×400 深色背景(對齊 Wails 控制台 splash 配色
- Makefile
dmg拆成三個 target:dmg:auto-detect,有 create-dmg 走 fancy,沒有 fallback plain(CI 無痛)dmg-fancy:強制美化版(需brew install create-dmg)dmg-plain:原本的 hdiutil UDZO(保留為 fallback)
- Windows / Linux 流程零改動
驗證:
brew install create-dmg成功make dmg-fancy產出 157MB DMG,mount 後內容:app + Applications 捷徑 + .background/background.png + .DS_Store(視窗樣式)hdiutil verify通過
🔴 2026-04-14 使用者提出 L 級重大方向變更
使用者原話
推論只需包含這三種 camera/image/上傳影片(avi, mpeg, mp4, 瀏覽器能吃的格式) 模型除了預設的幾種只能用上傳的 介面希望是用網頁而不是包在應用程式中 我想像中的是 visionA local 安裝完 啟動後 應用程式介面會有可以顯示 local server log 的地方 有可以啟動/停止 重啟 local server 的介面 有打開 localhost 網頁的介面 網頁上會有 scan/connect device 的介面 選模型/上傳模型 推論的介面
變更解讀
- 推論來源範圍縮減:camera / image / 上傳影片,砍掉 URL 推論 + yt-dlp + YouTube/Vimeo
- 模型管理縮減:只保留「預設幾種 + 只能上傳」,砍掉任何 URL 下載 / Model Zoo 類功能
- 介面架構巨變:Wails 桌面 app 退化為「Local Server 控制台」(Log 面板 + Start/Stop/Restart + Open browser),真正的使用介面在瀏覽器跑(scan/connect/model/inference 全在 Web UI)
影響範圍(初判)
- 砍 yt-dlp 打包(M6 部分)→ 依賴瘦身 -35MB
- 砍
ResolveWithYTDLP/ytdlpHosts/StartFromURLyt-dlp 路徑 / 前端 URL tab - Wails 控制台是全新 UI,和現有 splash + Next.js 完全不同
- 與第三輪決策 Q-A(砍 tray)、Q7(關閉視窗=結束 app)有潛在衝突,可能要復議
- M1-M7 的工作大部分仍可沿用(server / Next.js UI / 打包)只是 Wails 視窗內容要重寫
- 延伸的 yt-dlp 跳頁 bug 問題自動消失(功能直接砍)
第一輪三方分析狀態
- ✅ PM 分析完成:
01-requirements/pm-analysis-round2-refactor.md(419 行) - ✅ Design 分析完成:
03-design/design-analysis-round2-refactor.md(537 行) - ✅ Architect 分析完成:
04-architecture/architect-analysis-round2-refactor.md(798 行)
三方共識(無分歧)
- 技術可行,沿用率 85-95%,估 ~10 人天
- 砍 yt-dlp(vendor 35MB + resolver + URL tab),dmg 220→~135-185MB
- ffmpeg 保留(上傳影片仍需解碼),GPL blocker 延續,可能 M8 切 LGPL
- Q-A 砍 tray 必須復議 — 新方向下 tray 價值從「可有可無」變「核心」
- Q7 關閉=結束必須復議 — 否則關 Wails 視窗 = SIGTERM server = 瀏覽器 tab ECONNREFUSED
- Next.js UI 幾乎零改動(80-90% 沿用,只砍 URL tab)
- Wails 控制台走 vanilla HTML/JS/CSS(不新 Next.js mini app)
- CORS 要限制為 127.0.0.1/localhost(瀏覽器模式新攻擊面)
- 綁定維持 127.0.0.1,不做 LAN mode
- watchServer 改為 Error state,不 os.Exit
三方立場差異(待使用者裁決)
- C1 動機問題(PM 堅持前置條件):必須先知道使用者為什麼要改架構,PM 列出 9 種可能動機
- 首次啟動是否自動開瀏覽器:Design 建議預設自動(Ollama 式)、PM 建議手動(C6 選 A)— 輕微分歧
- First-Run 搬家策略:PM 建議留瀏覽器端(C8 選 A)、Design 沒強烈意見
下一步
- ✅ 使用者決策 R5 全部收齊(見下方「R5 第五輪使用者決策」)
- ⏳ 三方依決策產出正式 PRD v2 / Design Spec v2 / TDD v2(下一步)
- ⏳ 三方互審 → 使用者確認 → 進開發
R5 第五輪使用者決策(2026-04-14,重構方向變更)
| # | 題目 | 使用者決定 | 備註 |
|---|---|---|---|
| R5-1 | 重構動機 | A + B + G(多視窗便利 + 瀏覽器 devtools + 需求方就是這麼要求) | 純 127.0.0.1,無 LAN / 無背景 daemon 需求 |
| R5-2 | Wails 視窗關閉行為(Q7 復議) | 維持關閉=結束 server,瀏覽器網頁顯示「local server 已離線」覆蓋層 | 不改原 Q7 決策,但前端要新增「server 離線」UI |
| R5-3 | Tray 復議(Q-A 復議) | T1:維持砍 tray | 和 R5-2 一致,省 1.5 人天 |
| R5-4 | 首次啟動自動開瀏覽器 | A:首次自動開,之後可設定 | Ollama 式零摩擦 |
| R5-5 | Wails 控制台 scope | 同意 PM 清單,拿掉 Mock 模式切換 | |
| R5-5a | Mock 模式歸處 | A:完全砍掉 Mock 模式 | 使用者明確:「沒插硬體就讓它是空的,不用 demo」 |
| R5-6 | ffmpeg 授權 | LGPL 方案 B(混合) | Windows/Linux 用 BtbN 現成 LGPL binary,macOS 自 build |
| R5-6a | macOS build 規模 | A:最小 decoder-only build(~20MB) | 只含 mp4/avi/mov/mpeg/mpg 五種解碼器 |
| R5-6b | macOS binary 存放 | ① commit 到 repo(vendor/ffmpeg/macos/) |
LGPL ffmpeg 幾乎不需更新,直接進 git |
| R5-6c | 是否打包 ffprobe | 一起包 | BtbN 本來就都有,0 成本 |
| R5-7 | M7 Windows build | 先不管,做完再驗 | 跳過 M7-B3 baseline 驗證 |
三方共識全部採納(無須使用者裁決)
- 技術可行,沿用率 85-95%,~10 人天
- 砍 yt-dlp 全套(vendor 35MB + resolver + URL tab + handler)
- ffmpeg 保留(因 R5-6 走 LGPL,GPL blocker 解除)
- Next.js Web UI 80-90% 沿用,只砍 URL tab
- Wails 控制台走 vanilla HTML/JS/CSS(不新 Next.js mini app)
- CORS 限制為 127.0.0.1/localhost
- 綁定維持 127.0.0.1(不做 LAN mode)
- watchServer 改為 Error state,不再
os.Exit(1) - 預設模型維持 8 個 .nef(「只能上傳」= 再次確認不做 Model Zoo)
- 批次影像上傳保留
- 上傳影片副檔名:
.mp4 / .avi / .mov / .mpeg / .mpg - Server port、資料目錄、版本號、清 log 等工具資訊住 Wails 控制台
- 硬體偵測結果、上傳模型、Settings > 語言 住瀏覽器 Web UI
- Restart 期間瀏覽器 tab 用
boot-id+ retry 重連(雖然 R5-2 選關閉=結束,此邏輯仍需做以支援 Restart Server 按鈕)
三方正式 v2 文件(已產出)
- ✅ PRD v2.0:
02-prd/PRD-v2.md(484 行)— PM 5 個懸念見 §11 - ✅ Design Spec v2.0:
03-design/design-spec-v2.md(99 行索引)+03-design/v2/*.md(5 子檔) - ✅ TDD v2.0:
04-architecture/TDD-v2.md(136 行索引)+04-architecture/v2/*.md(8 子檔,~3738 行)
三方 v2.1 補丁(已產出,吸收 R5-D + R5-E + 互審發現)
- ✅ PRD v2.1(原地更新 PRD-v2.md,500 行,卡在上限)
- ✅ Design Spec v2.1:索引 127 行 + settings-update 239 + control-panel 465 + 新檔 startup-progress 417
- ✅ TDD v2.1:索引 162 行 + control-panel 830 + server-lifecycle 961 + web-ui-offline-overlay 更新 + deletions 更新 + milestone-plan 更新 + 新檔 startup-pipeline 518
- 新工時預估:10 → 12 人天(+M8-4 +0.5 / +M8-4b +1 / +M8-7 +0.3 / +M8-10 +0.2),建議對外回報 ~13 人天含 buffer
v2.1 新增懸而未決問題彙總
Design 新增(3 題):
- D-Q1:20 秒 retry hint 文案「正在重試…」vs「正在處理中…」(Design 建議前者)
- D-Q2:WebSocket 被安全軟體擋的提示(Design 建議不做特殊偵測)
- D-Q3:Retry 按鈕語意「重置整個啟動」vs「重試當前階段」(Design 建議重置,需 Architect 確認 RestartStartupSequence 可行)
Architect 新增(5 題):
- A-Q1:階段 6 WebSocket 首次連線實作方式 long-poll endpoint vs sentinel file(交 M8-4b 執行者)
- A-Q2:watcher goroutine 和使用者在 Starting 中按 Stop 的 race(action bar 禁用,M8-4b 實測)
- A-Q3:shutdownGracePeriod 7s/6s 對齊若實測常被 SIGKILL 則改 9+1 秒
- A-Q4:Linux notify-send 不存在時的 fallback(M8-10 實測 Ubuntu minimal)
- A-Q5:N-R4 CI/E2E 測試分層(blocked on testing agent)
PM 保留:
- §11-4 N-R4 CI/E2E 測試分層(同 A-Q5)
- §11-7 R5-E 6 階段中英雙語文案定稿(Design 已定版,使用者最後可 override)
第二輪三方互審結果(2026-04-14)— 🟢 全員通過
- ✅ Design 審 PRD v2.1:通過,3 Minor 不阻擋(Error 按鈕命名 / Linux OFF 階段描述 / v2.0 歷史字樣)
- ✅ PM 審 TDD v2.1:通過,2 Minor 不阻擋(code-reuse-v2.md:92 殘留 / milestone-plan.md:6 工時數字不同步)
- ✅ Architect 審 Design Spec v2.1:通過,3 Minor 全在 TDD 側(skipped status 枚舉 / WS sentinel file 決案 / 階段 6 soft timeout skip + Retry 機制)
第二輪關鍵仲裁
- Error 按鈕命名分歧:Architect 仲裁為兩個獨立動作
- Startup error(60s timeout 或階段失敗)→ 按鈕「Retry」= 呼叫
RestartStartupSequence()重置整個啟動流程 - Running 階段 watchServer 失敗 → 按鈕「Restart Server」= 重 spawn server(既有行為)
- Startup error(60s timeout 或階段失敗)→ 按鈕「Retry」= 呼叫
- D-Q3 RestartStartupSequence 可行性:✅ 可行,新增 function(5 步驟實作細節已定)
- 停 watcher → ForceKill server → 重置 state machine → 重建 pipeline → 重跑 Start
- 階段 1 直接 Complete 不重跑
- sentinel file 必須先清
- Retry 情境下 port 允許 fallback(cold start 行為)
- 階段 6 WebSocket 就緒偵測方案:採 sentinel file
<dataDir>/.first-ws-connected(不用 long-poll endpoint) - D-Q2 WebSocket 被擋偵測:不可行,不做特殊偵測
- D-Q1 20s retry hint 文案:不影響技術,Design 自由定稿
Architect 自補 TDD 清單(M8-4b 前補完,估 1-2 小時,不啟動新 Agent)
第一輪遺留 4 項 + 第二輪新增 3 項:
- offline-overlay 10s/2 次/3s active polling 參數
- Gin SkipPaths + crypto/rand boot-id
- Restart 強制同 port 規則
- ExportLog binding
StartupProgressEvent.Status新增"skipped"枚舉值- 階段 6 WebSocket sentinel file 決案寫入
- 階段 6 Toggle OFF 時跳過 soft timeout + 新增 §9「Retry 機制」小節(含 RestartStartupSequence)
v2.1 殘留 Minor(不阻擋開發,M8 過程中順手修)
04-architecture/v2/code-reuse-v2.md:92殘留「新增 autoOpenedThisSession 欄位」字樣(轉版漏改)04-architecture/v2/milestone-plan.md:6摘要「~11.5 人天」和 L491 合計「12.0」不一致- PRD v2.0 變更紀錄列殘留「首次自動開瀏覽器」(歷史紀錄,不修)
M8 開發進度(2026-04-15)— 🟢 程式碼全部完成,只差 M8-10 交付
| Milestone | 狀態 | 備註 |
|---|---|---|
| Architect 自補 TDD 7 項 | ✅ 完成 | 7 項落地 + 意外發現(FAILURE_THRESHOLD 同步、ForceKill 缺失提醒、hard timeout skip) |
| M8-1 砍 yt-dlp | ✅ 完成 | +222/-555 行,18 檔案,5 項 build 全綠 |
| M8-2 砍 Mock | ✅ 完成 | -528 行,15 檔案,5 項 build 全綠,smoke test 通過 |
| M8-3 ffmpeg LGPL | ✅ 完成 | ffmpeg 5.7MB + ffprobe 5.6MB(比 GPL 版省 85% 空間),LGPL 合規,build 2m44s |
| M8-1+M8-2 Reviewer | ✅ 通過 | 親自 build/test/smoke,0 誤刪 0 殘留 |
| M8-3 Reviewer | ✅ 通過 | 18 項驗證全過,1 Minor + 2 Suggestion + 3 交付前事項 |
| M8-4 ServerController + log ring buffer | ✅ + Review 通過 + 4 Major 補丁 | 20 unit test + race -count=2 全綠 |
| M8-4b 啟動階段管線 | ✅ + Review 通過 + 3 Major 補丁 | 14+3 test,HasFailedStage / IsInColdStart helpers |
| M8-5 Wails 控制台 UI | ✅ + Review 通過 + 2 Critical 補丁 + Stage 6 CTA 補丁 | 9 檔 ~2012 行,wails build PASS |
| M8-6 source-selector 副檔名擴充 | ✅ 完成(未 Review 改動太小) | 4 檔案 ~4 行 |
| M8-7 Offline Overlay | ✅ + Review 通過 | role=alertdialog + focus trap + wsEverConnected 容錯 |
| M8-8 CORS middleware | ✅ + Review 通過 | 127.0.0.1/localhost + suffix attack 防護 |
| MAJ-4 shutdown broadcast | ✅ + Review 通過 | server/ws + visiona-local/notify helper,15 test |
| M8-9 Boot-ID + tab 重連 | ✅ + Review 通過 | 9 test + SSR 相容 + reload loop guard |
| M8-10 端到端 smoke test + 三平台 build | 🔄 進行中 | macOS build ✅ + P0 latent bug 修復 ✅(預設 15 模型載入),待 Reviewer + Windows/Linux 驗證 |
M8-3 Reviewer 交付前必做事項(M8-10 前)
- ✅
vendor/ffmpeg/macos/4 檔 git add — 已於 commit8cd5751處理 - ✅ 重跑
make payload-macos(2026-04-15)— payload/darwin 204MB(原 GPL 版 ~280MB),LGPL 驗證通過,ffmpeg 5.7MB + ffprobe 5.6MB,無 yt-dlp 殘留 - ✅
vendor/yt-dlp/87MB 殘留 — 已清除
M8-10a macOS build + smoke test 結果(2026-04-15)
✅ 通過項:
make dmg成功:163MB(GPL 版 220 → LGPL 版 163,-57MB,符合 PRD v2.1 預估).appbundle 215MB,codesign verify OK- LGPL ffmpeg config 驗證:
--enable-version3+ 無--enable-gpl+ 無 libx264/libx265,只含 mp4/avi/mov/mpeg/mpg 所需 demuxer/decoder(符合 R5-6a 最小 decoder-only build) - Server 從 bundle 正常啟動(127.0.0.1:3799)
VISIONA_BUNDLE_BIN_DIRPATH 注入正確deps/checker.go已檢查 ffprobe(progress.md 舊標「⏳ 待補」實際已做,標記更正)[OK] ffmpeg: (bundled)✅[OK] ffprobe: (bundled)✅[OK] python3: Python 3.14.3✅
GET /→ HTTP 200 size=24292(Next.js 首頁)✅ splash regression 不再發生GET /api/system/health→{"status":"ok"}✅GET /api/system/deps→ 三項全 available ✅GET /api/devices→ 200(空陣列,無裝置)✅- SIGTERM 優雅關閉 ✅
- CORS middleware init 無錯 ✅
🔴 M8-10a 抓到的 P0 latent bug(從 M1 就有,只是沒人測過)
現象:GET /api/models → {"data":{"models":null,"total":0},"success":true}
啟動 log:Loaded 0 built-in models + Warning: could not load models from .../bin/data/models.json: no such file
根因(server/main.go:42-51 + :99-108):
- server 預設
base = filepath.Dir(exe)=Contents/Resources/bin/ - 預設
dataDir = base + "/data"=Contents/Resources/bin/data/(空目錄) - 但 models.json + 8 個 .nef 實際住在
Contents/Resources/data/(上一層) - Wails 端
server_control.go:529明確傳--data-dir a.dataDir,而a.dataDir = platformDataDir()=~/Library/Application Support/visiona-local/— 使用者 dataDir,也沒有 models.json(user dataDir 只存 lock / ipc-port / logs / custom-models / preferences.json) - 結論:正式啟動路徑下永遠載入 0 個預設模型
為什麼 M1-M7 都沒抓到:當時 smoke test 只測 /api/health、/、splash 跳轉,從沒跑過 /api/models。
這違反 R5 第 9 點共識:「預設模型維持 8 個 .nef(只能上傳 = 再次確認不做 Model Zoo)」— 8 個預設模型必須能載入,使用者才有基本 demo 體驗。
影響範圍:macOS / Windows / Linux 三平台都同樣這個 bug(server/main.go 是共用的)。
採方案 B(使用者批准)+ 額外職責拆分(2026-04-15)
實作:server/main.go
- 新增
resolveBuiltInDataDir(base)— 照resolveBridgeScript同款風格,依序試<base>/data→<base>/../data→<base>/../Resources/data,以models.json存在為命中條件 main()拆出兩個獨立變數:builtInDataDir(read-only,bundle 內)— 給model.NewRepository(filepath.Join(builtInDataDir, "models.json"))與flash.NewService(deviceMgr, modelRepo, builtInDataDir)使用(因 flash 也要解析 model.filePath 相對路徑"data/nef/...")dataDir(writable,user home)— 給 custom-models / sentinel file / logs 使用,語意不變
cfg.DataDir == ""時 fallback 成builtInDataDir(保 dev modego run ./server繼續可跑)
為什麼順便拆職責:原本的 bug 不只影響 modelRepo,也影響 flash.Service(flash.service.go:115-121 拿 s.dataDir 解析 "data/nef/kl520/xxx.nef" → 原本會指向 user dataDir 找不到檔案)。純 B 只修 main.go 一處還不夠,必須同時把 flash 切到 builtInDataDir。拆成兩個變數反而讓職責更清楚,未來不會再混淆。
驗證結果:
go build / vet / test -count=1 ./...全綠- 重 build dmg 163MB(大小不變)
- Smoke test
/api/models→total: 15(不是原估計的 8,因為 models.json 有 15 個條目,部分 model 共用 nef) ✅ - 啟動 log:
Built-in data dir: .../Contents/Resources/data+Loaded 15 built-in models+ 無could not load modelswarning /api/models/kl520-yolov5-detection回傳完整 metadata + filePathdata/nef/kl520/kl520_20005_yolov5-noupsample_w640h640.nef- flash 解析後指向的實體檔案在 bundle
.../data/nef/kl520/kl520_20005_yolov5-noupsample_w640h640.nef(7.2MB)與kl720/...(10MB),與 API 回傳的 modelSize 完全吻合 ✅
Reviewer 第一輪(2026-04-15):⚠️ Major 1 / Minor 2 / Suggestion 2
報告:.autoflow/05-implementation/reviews/review-m8-10a-builtin-data-dir-fix.md
- Major-1:Linux AppImage 布局(
usr/bin/<exe>+usr/lib/visiona-local/data/)三候選全不命中;AppRun 已 exportVISIONA_BUNDLE_LIB_DIR但 server 沒讀。備註resolveBridgeScript先前就有同樣缺失。 - Minor-1:fallback 沒
filepath.Abs化 - Minor-2:fallback 沒 log 試過的候選
- Suggestion s-1:抽公用
findFirstExistinghelper - Suggestion s-2:dataDir dev mode fallback 註解
Reviewer 第二輪修復(2026-04-15):Major + 所有 Minor + 兩個 Suggestion 一次全部處理
- 新增
findFirstExisting(candidates, sentinel) (dir, tried)helper(s-1) resolveBuiltInDataDir候選 5 條:①envVISIONA_BUNDLE_LIB_DIR/data②<base>/data③<base>/../data④<base>/../Resources/data⑤<base>/../lib/visiona-local/dataresolveBridgeScript比照修復(技術債一起清),候選 6 條- fallback 全
filepath.Abs化(m-1)+log.Printf("warn: ... Tried: %v", tried)(m-2) main()dataDir fallback 加 5 行註解解釋 dev-only 語意(s-2)
第二輪 Review(2026-04-15):✅ 通過,可交付三平台
- 逐項驗證:Major-1 ✅ / Minor-1 ✅ / Minor-2 ✅ / s-1 ✅ / s-2 ✅
- 獨立複驗:build / vet / test 全綠;AppImage 模擬(env var 路徑)✅;AppImage 模擬(FHS fallback 無 env)✅;全不命中情境 log + fallback + server 不 crash ✅;
os.Chdirgrep 零匹配(./scripts相對候選無 cwd 漂移);候選順序對非 Linux 三平台零誤命中 - 新發現兩項非阻擋:
- Minor m2-1:resolve 函式用 std
log.Printf而非pkglogger.Warn(logger 尚未初始化前呼叫,合理),下次 logger 重構時統一 - Suggestion s2-1:
findFirstExisting可改(dir, tried, ok bool)更 idiomatic,非必須
- Minor m2-1:resolve 函式用 std
M8-10b/c 待使用者驗證
- Windows:使用者在 Windows 實機跑 bootstrap + make exe → 驗證 splash → Wails 控制台 6 階段啟動 → 瀏覽器 Web UI
- Linux:Ubuntu 實機跑 bootstrap-linux.sh + make appimage → 驗證 xdg-open 預設 OFF + notify-send fallback
M8-3 Minor + Suggestion(低優先)
- Minor:BUILD.md §Verification §5 預期
spctl --assess=accepted實測會被 reject,改為codesign -v - Suggestion 1:
vendor-ffmpegtarget 可補 sha256 對比防呆 - Suggestion 2:
payload-windows授權檔skipifsourcedoesntexist若同時缺失會無授權交付
上一輪 Reviewer 提的 Minor(已解決 / 懸而未決)
- ✅
source-selector.tsxaccept 清單已擴充 mpeg/mpg(M8-6 完成) - ✅
camera_handler.go後端副檔名白名單已擴充(M8-6 完成) - ⏳
deps/checker.go未加 ffprobe 檢查 — M8-3 後可補 - ⏳
api_e2e_test.go整檔刪後失去 HTTP 層 smoke — 建議 M8-10 前補一份不依賴 mock 的 read-only e2e
M8-4 Reviewer 結果:⚠️ 需修 5 Major(2026-04-15)
親跑驗證全綠:go build/vet/test/test -race、20 unit test、smoke test、SkipPaths 生效。
5 個 Major(4 個 M8-4 Agent 回修、1 個留 M8-4b 包辦):
- MAJ-1
server_control.go:198-229 / 251-265Stop/ForceKill 不 cancel watchCancel → 30s 後誤翻 Error + 發崩潰通知 - MAJ-2
server_control.go:269-291handleWatchFailure 未取 txMu → 與 Stop race - MAJ-3
server/main.go:166shutdownFn timeout 仍 10s,TDD §8.1 要求 6s(破壞 7+1 modal UX) - MAJ-4 沒實作
server:shutdown-imminentWebSocket 廣播(阻擋 M8-9,不阻擋 M8-4b/5/7)→ M8-4b 一起做 - MAJ-5
server_control.go:579-608logPump scanDone 不 drain lineCh → 丟最後 128 行崩潰 log
M8-4 Reviewer 15 個 Minor(技術債,M8-5 後整理)
主要:Snapshot 效率、ShouldEmit CAS micro-race、Restart 拆兩段 txMu、stopGraceful 與 logPump file handle race、scanner select default、notify timeout、v1/v2 重複碼
v1/v2 並存策略
合理但需立即標記砍除時程。v1 路徑(stopServer/stop()/kill()/watchServer/5s grace)已 dead code 但仍存在易誤用 → M8-5 完成後立即砍 v1(含 MIN-10/11/12 併處理)
待使用者決策
- commit 策略:Reviewer 建議分三個 commit(M8-1 / M8-2 / M8-3),或一個合併。使用者從未要求 commit,保守做法是先不 commit 等使用者說。
R5-Design 補充決策(2026-04-14,Design v2 產出後使用者回答)
| # | 題目 | 使用者決定 |
|---|---|---|
| R5-D1 | Server 崩潰時除了控制台 Error banner 是否仍發 OS 原生通知 | 保留 OS 通知 |
| R5-D2 | Linux 預設「啟動時自動開瀏覽器」 toggle 狀態 | 預設 OFF(macOS/Windows 預設 ON),避免 xdg-open 在極簡 WM 異常 |
| R5-D3 | R5-4 字面歧義「首次啟動」vs「每次啟動」 | 每次啟動都自動開瀏覽器(修正 R5-4 原本「首次」的字面,實際意圖是「每次 Start Server 成功後」) |
三方交叉審閱階段(進行中)
- ⏳ PM 審 TDD v2:驗證所有需求都有技術方案,R5 / R5-D 全部落地
- ⏳ Design 審 PRD v2:驗證體驗面沒遺漏,R5-D1/D2/D3 有無落地
- ⏳ Architect 審 Design Spec v2:驗證設計技術上可行
使用者授權
使用者已說「交互 review 完就進開發」— 審閱無衝突則直接進 M8,不用另外確認。
三方互審結果(2026-04-14)
Design 審 PRD v2:❌ 不通過(02-prd/reviews/design-review-of-prd-v2.md)
- Major 4 / Minor 4
- 核心問題:R5-D1/D2/D3 都沒吸收(PM 寫 PRD 時還不知道這三題)
- Major 4 auto-open toggle 位置分歧 → Design 仲裁「PRD 對(住 Wails 控制台)」,Design Spec v2 settings-update.md 要自修
- §11-5 徽章決定:不加
- Architect Q6 Overlay close tab 決定:不設
PM 審 TDD v2:⚠️ 條件通過(04-architecture/reviews/pm-review-of-tdd-v2.md)
- Major 4 / Minor 5
- 核心問題:R5-D 三題 TDD 零匹配 + M8-9 驗收條件
autoOpenedThisSessionflag 和 R5-D3 相反(per-session-once 寫成成功條件,Reviewer 會誤判) - PM 自行回答 PM §11 技術懸念:
- AC-1.3 10 秒預算不可達(估 5.5-18 秒)→ 建議放寬到 15 秒
- idle RAM ≤ 450MB 可達(估 275-405MB)
- PM 對 Architect Q4 grace period 回答:7 秒 + 1 秒內顯示「停止中…」modal(基於 Nielsen Norman 10 秒注意力臨界點)
- PM 判斷 M8-1/M8-2/M8-3 互不依賴,可在 Major 修復前先啟動(砍 yt-dlp / 砍 Mock / ffmpeg LGPL vendor)
Architect 審 Design Spec v2:⚠️ 有條件通過(03-design/reviews/architect-review-of-design-spec-v2.md)
- Major 2 / Minor 12
- Major 1:Design settings-update.md §2.2 誤稱「走 Wails 既有 settings store」(Wails v2 無此機制)+ 檔名不一致 → 採 TDD 的
preferences.json @ <dataDir>/ - Major 2:R5-D2 Linux 預設 OFF 兩份 spec 都沒落地 → 新增
DefaultPreferences()依runtime.GOOS - Architect 7 懸念自決:
- Q1 grep 確認
NewVideoSourceFromURL只有StartFromURL+videoIsURL-guarded seek handler 呼叫 → 整組砍(含videoIsURLfield) - Q3
crypto/rand16 bytes → hex(不引入 google/uuid) - Q5 navigator.language fallback:zh* → zh-TW / en* → en-US / else → zh-TW
- Q7 preferences JSON 用 write-rename atomic pattern
- Q1 grep 確認
- Architect 對 PM §11 回答:
- §11-1
preferences.json@<dataDir>/,write-rename 原子寫,fallback DefaultPreferences - §11-2 樂觀 ~4s / 悲觀 ~8s 達標,但 Windows + Defender 最壞 ~11s 可能超時,建議 M8-10 實測,超時則 AC-1.3 放寬到 12 秒(Architect 說 12,PM 說 15,差 3 秒)
- §11-3 idle RAM 樂觀 ~370MB 達標,悲觀 ~500MB 超 50MB,建議 PRD clarify「450MB 不含 browser tab」
- §11-1
- 關鍵發現 F-2:Restart Server port 保留 — TDD 允許 fallback 到 3722 會讓瀏覽器 tab URL 過期導致 Offline Overlay 永卡 → Restart 強制保留舊 port,不可 fallback,用不了就進 Error state(Architect 自補)
- 關鍵發現 B-1:watchServer 改 Error state 時等於砍掉 OS 通知(違反 R5-D1)→ 新增
sendCrashNotification()non-blocking toast(新檔visiona-local/notify.go,Architect 自補)
R5-E 追加決策(2026-04-14,互審結論後使用者追加)
使用者把「AC-1.3 時間預算」問題從「要多快」翻轉成「讓使用者感覺進度有在推動」— 採 Nielsen Norman perceived performance 原則而非硬時間指標。
| # | 決定 |
|---|---|
| R5-E1 | AC-1.3 時間上限放寬到 60 秒(原 10 秒),原則是 perceived performance > 硬時間指標 |
| R5-E2 | 啟動全程必須有階段化進度顯示:每個階段有編號 / 動作描述 / 視覺回饋 / 中英雙語文案 |
| R5-E3 | 任一階段卡超過 20 秒要顯示「正在重試」類提示,不可白畫面 |
| R5-E4 | 超過 60 秒總上限仍未就緒 → 進 Error state(和 watchServer 3 次失敗一致),顯示重試 / 回報 / 檢視 log 三按鈕 |
| R5-E5 | 階段文字由 Design Agent 決定(使用者授權)— 使用者最後審 wireframe 時可以 override |
| R5-E6 | 瀏覽器就緒偵測採 WebSocket 連上訊號(不做新 endpoint,不做固定延遲),WebSocket hub 收到第一個 client 連線視為第 6 階段「ready」 |
啟動階段建議(6 階段,Design 最終定版)
- 初始化 Wails 控制台
- 檢查 Python runtime + 驅動
- 啟動本機伺服器(port binding)
- 偵測 Kneron 裝置
- 開啟瀏覽器
- 瀏覽器就緒(WebSocket 連上)
技術影響(三方 v2.1 補丁輪要吸收)
- 新增 Wails event:
startup:progress {stage, label_zh, label_en, status} - 新增 Wails event:
startup:stage-timeout {stage}(20 秒卡住觸發) StartServer()改為階段化,每個階段 emit event- Wails 控制台 vanilla JS 要訂閱 event 更新進度面板
- 新增啟動進度面板 UI(Design Spec v2.1 wireframe)
- M8-4/M8-5 工時可能 +0.5-1 天
修正計畫(v2.1 補丁輪)
- PM → PRD v2.1:補 R5-D1/D2/D3、Minor 1-4、AC-1.3 放寬到 12 秒、idle RAM 加註「不含 browser tab」
- Design → Design Spec v2.1:
- settings-update.md 修 Major 1+2(
preferences.json @ <dataDir>/+DefaultPreferences()平台差異) - control-panel.md §4.4 log 1000→2000 / §6.2 補 OS notification + Report 按鈕 hold 註記 / §7.1 第 5 步「首次→每次」
- settings-update.md 修 Major 1+2(
- Architect → TDD v2.1:
- R5-D1 sendCrashNotification 實作(新檔 notify.go)
- R5-D2 DefaultPreferences 依 GOOS
- R5-D3 砍 autoOpenedThisSession flag,每次 StartServer 都 trigger OpenInBrowser
- M8-9 驗收條件修正(移除「Restart 不會二次開」條件)
- Restart 同 port 規則
- PM §11-1/2/3 寫入 TDD
- Q4 grace period 採 PM 7 秒 + 1 秒 modal 建議
- Q1/Q3/Q5/Q7 自決結果寫入
以下是 2026-04-12 之前的進度快照,保留備查。變更確認後需要全面更新。
🎉 M1 達成總結
dist/visiona-local.dmg(70MB) 可雙擊安裝- 全新環境下能 mount → 拖到任意位置 → 雙擊執行
- Mock 模式 server 子程序自動啟動(Bundle 內
Resources/bin/visiona-local-server) - API endpoints 全部 200:health、info、devices、models
- 乾淨退出(SIGTERM → 5s → SIGKILL)
- 資料目錄:
~/Library/Application Support/visiona-local/(lock + ipc-port + logs + custom-models) - 第三輪 P0 bugs 修復:(1) APFS case-insensitive 自我毀滅、(2)
--pythonflag 不存在、(3)Resources/bin/路徑漏bin/子目錄
M1 收尾(C 已完成)
- ✅
GET /404 修復:Makefile 加build-embedtarget,把 frontend/out → server/web/out 同步,再 build server binary。dmg 71MB 含完整主 UI(21KB 首頁 + Next.js chunks)
M2-M6 任務清單(使用者選 Y:全包,macOS 為主)
M2 — i18n + Settings 分頁調整
| # | 任務 | 狀態 |
|---|---|---|
| M2-1 | i18n 中英雙語切換 | ✅ |
| M2-2 | Settings 4 分頁重構 | ✅ |
| M2-3 | 清 cluster.* i18n keys | ✅ |
| M2-4 | sidebar Workspace 接 i18n | ✅ |
| M2-5 | rebuild dmg + smoke test | ✅(71MB, root+settings 200, server 從 bundle Resources 起) |
M3 — Python runtime 策略 A 內嵌 + KneronPLUS wheel
| # | 任務 | 狀態 |
|---|---|---|
| M3-1 | vendor-python (PBS 3.12.9, 15MB) | ✅ |
| M3-2 | vendor-wheels (9 wheels, 71MB) | ✅ |
| M3-3 | ensureBundledPython() 實作 | ✅ |
| M3-4 | payload-macos stage python + wheels | ✅ |
| M3-5 | dylib codesign | ✅ 不需要(Gatekeeper 沒擋) |
| M3-6 | rebuild dmg + smoke test | ✅ 157MB, venv + 9 wheels + import kp 全通過 |
M6 — ffmpeg + yt-dlp 內嵌(完整離線)
| # | 任務 | 狀態 |
|---|---|---|
| M6-1 | vendor-ffmpeg | ✅(77MB GPL build, 由 VISIONA_ALLOW_GPL_FFMPEG flag 放行) |
| M6-2 | vendor-ytdlp | ✅(35MB, yt-dlp 2026.03.17) |
| M6-3 | payload-macos stage ffmpeg + yt-dlp | ✅ |
| M6-4 | server internal/deps/ env var 偵測 | ✅(VISIONA_BUNDLE_BIN_DIR) |
| M6-5 | rebuild dmg | ✅ 220MB |
🔴 P1 release blocker:ffmpeg 授權
- macOS 上現成的 ffmpeg static binary 全部都是 GPL build(含 --enable-gpl --enable-libx264)
- 使用者決定 B:暫定使用 GPL build,發佈前由法務 review
- 必須在 PRD 第三方授權頁明確標
ffmpeg: GPL build (under legal review) - 替代方案保留:自 build LGPL(需 build pipeline)/ online download / 砍 ffmpeg 功能
M4 / M5 — Windows / Linux(無法在這台 Mac 驗證,僅寫 script)
| # | 任務 | 狀態 |
|---|---|---|
| M4-1 | Inno Setup .iss script | ✅ installer/windows/visiona-local.iss |
| M4-2 | Makefile wails-windows / exe target | ✅ uname 守門 |
| M4-3 | payload-windows | ✅ 在 macOS 上跑通 vendor 部分(378MB) |
| M5-1 | build-appimage.sh | ✅ installer/linux/build-appimage.sh |
| M5-2 | Makefile wails-linux / appimage | ✅ uname 守門 |
| M5-3 | payload-linux + udev rule | ✅ installer/linux/99-kneron.rules + install-udev.sh,在 macOS 上跑通 vendor(317MB) |
lifecycle 補件(M1+ TODO 移入 M2-M6 末尾)
| # | 任務 | 狀態 |
|---|---|---|
| L-1 | watchServer() 每 10s health check | ✅ 連續 3 次失敗 emit server:dead event |
| L-2 | Fatal 原生對話框 | ✅ macOS osascript / Win PS / Linux zenity-kdialog-stderr |
| L-3 | Wails /ipc/raise endpoint | ✅ 隨機 port + wails-ipc-port 檔案 |
| L-4 | stale process 清理 | ✅ macOS/Linux lsof+ps;Windows 留 TODO |
M7 — Windows 實機 build + splash regression 修復(2026-04-12)
M7-A:Windows 一鍵 build 工具鏈(使用者在 Windows 機器上實機跑 bootstrap)
新增 local-tool/scripts/bootstrap-linux.sh + bootstrap-windows.ps1,目標是使用者 clone repo 後一行指令完成依賴安裝 + vendor 下載 + payload 打包 + wails build + installer 產出。
| # | 任務 | 狀態 |
|---|---|---|
| M7-A1 | 統一專案目錄名為 local-tool(連字號),清掉所有 local_tool 殘留 |
✅ |
| M7-A2 | bootstrap-linux.sh(apt + go 1.22.5 + node 20 + pnpm + wails) | ✅ 未在 Ubuntu 實機驗證 |
| M7-A3 | bootstrap-windows.ps1(winget 安裝 git/go/node/python/msys2/inno setup + build) | ✅ Windows 實機驗證通過 |
Windows build 踩坑紀錄(每個都修好並 push):
- PowerShell 5.1 不支援
&&→ 改用陣列 +-join ' && ' - 中文亂碼 → ps1 加 UTF-8 BOM
pip3: command not found→ Makefile 偵測 pip/pip3/python -m pip+ bootstrapMSYS2_PATH_TYPE=inherit讓 bash 繼承 Windows PATHunzip: command not found→ Makefile 改用 Python zipfile 解壓,移除 unzip 依賴server.exe沒 build → 新增build-server-windowscross-build target- Microsoft Store
python3stub → Makefile 偵測時排除*WindowsApps*路徑,bootstrap 主動找真實 Python 並以VISIONA_PYTHON環境變數傳入 /tmp/ffmpeg-win.zip路徑問題 → Windows 版 python.exe 不懂 MSYS2 的/tmp,改用相對路徑vendor/ffmpeg/windows/ffmpeg-win.zip- Inno Setup
ISCC.exe找不到 → winget 裝到 user-scope%LOCALAPPDATA%\Programs\Inno Setup 6\,非傳統Program Files (x86)。Find-Iscc 多層偵測 + 新增ISCC環境變數 override + user-scope 固定路徑 + 登錄檔 fallback ChineseTraditional.isl不存在 → Inno Setup 6.3+ 官方移除繁體中文語系,改用#ifdef WITH_TRAD_CHINESE條件宏,預設只用英文 installer UI(不影響 app 本身 i18n)make exe成功但 dist 空 → PS → bash quoting 問題,改寫 tmp.visiona-build.sh檔再執行;另外拆出exe-onlytarget 讓使用者刪掉 dist 能快速重跑 iscc 不重 build wails- Makefile
exerecipe 診斷輸出 → 印 cwd / iscc exit code / dist 內容,避免靜默失敗
成果:E:\visionA\local-tool\dist\visiona-local-0.1.0-windows-x64.exe 成功產出,iscc 正常 compile 通過。
M7-B:🔴 splash regression 修復(P0)
根因:visiona-local/frontend/ 是 M1 階段從 edge-ai-platform 複製過來的 installer wizard HTML/JS/CSS,整組沒清理。main.go 的 //go:embed all:frontend 直接把這堆 wizard 當 Wails 主視窗內容,使用者開 app 看到的是 Edge AI Platform Installer 而不是 Next.js 主 UI。
影響範圍:macOS dmg 也有同樣 bug,只是 M1 驗收時是用瀏覽器連 http://localhost:3721/ 驗證 server 回應,沒真的打開 Wails 視窗看 UI,所以 regression 一路混過 M1-M6 直到 Windows 實機驗證才被發現。
修法(commit 570e040,刪 1248 行 / 新增 79 行):
visiona-local/frontend/index.html→ 極簡 splash(logo + spinner + status)visiona-local/frontend/app.js→ ES module,輪詢GetServerStatus()binding,拿到running=true+url後window.location.replace(url + '/')跳到 Next.js 主 UIvisiona-local/frontend/style.css→ 深色 splash 樣式
Next.js 主 UI 完全不使用 Wails JS binding(純 HTTP API),從 wails:// 跳到 http://127.0.0.1:<port>/ 後功能完整可用。
| # | 任務 | 狀態 |
|---|---|---|
| M7-B1 | 清掉 frontend/ 的 edge-ai-platform wizard 殘留 | ✅ |
| M7-B2 | 改寫為 splash + redirect | ✅ |
| M7-B3 | Windows 實機重 build + 測試 splash → Next.js UI 跳轉 | ⏳ 待使用者驗證 |
| M7-B4 | macOS 重 build 驗證同樣修復有效 | ⏳ 待排程 |
專案概述
visionA-local 是 /Users/jimchen/Innovedus/edge-ai-platform 的 local 版本,目標是把原本要 deploy 到 EC2/staging Docker 環境的網頁工具,改造成可在本地單機執行的桌面應用,並打包成 GUI 安裝檔,支援 macOS / Windows / Ubuntu 三平台。
任務等級:L 級(完整流程)
進度表
| 階段 | 狀態 | 完成時間 | 備註 |
|---|---|---|---|
| 需求討論(三方聯合) | ✅ 已完成 | 2026-04-11 | 四輪討論 + 交叉審閱完成 |
| PRD | ✅ 已完成 | 2026-04-11 | v1.2 定稿 |
| 設計規格 | ✅ 已完成 | 2026-04-11 | 第四輪修訂定稿 |
| 系統架構 / TDD | ✅ 已完成 | 2026-04-11 | 第四輪修訂 + Plan B 補件 |
| 開發(增量式) | 🔄 進行中 | - | M1-M6 macOS ✅;M7 Windows build 完成,splash 修復待 Windows 驗證 |
| Review | ⏳ 待開始 | - | - |
| 測試 | ⏳ 待開始 | - | - |
| 打包 / 安裝檔 | 🔄 進行中 | - | macOS dmg ✅;Windows exe 成功產出(UI 待驗證);Linux AppImage 待 Linux 機器驗證 |
| 交付 | ⏳ 待開始 | - | - |
當前待辦
- 第一輪三方分析(已完成)
- 使用者回答 15 個關鍵決策問題(已完成)
- PM Agent 產出正式 PRD(2026-04-11)
- Design Agent 產出正式設計規格(2026-04-11)
- Architect Agent 產出正式 Design Doc + TDD(2026-04-11)
- 第三輪使用者決策(砍 tray、B4、C2、D2、E1/E2/E3)
- Design Agent 依第三輪決策修訂設計規格(2026-04-11)
- PM Agent 依第三輪決策修訂 PRD(2026-04-11)
- Architect Agent 依第三輪決策修訂架構文件(2026-04-11)
- bootstrap-linux.sh + bootstrap-windows.ps1(2026-04-12)
- Windows 一鍵 build 踩坑全清:11 項修好 push(2026-04-12)
- Windows
dist/visiona-local-0.1.0-windows-x64.exe成功產出(2026-04-12) - M7-B splash regression 修復(commit 570e040,2026-04-12)
- 使用者 Windows 重 build + 驗證 splash → Next.js 主 UI 跳轉
- macOS 重 build 驗證 splash 修復有效(之前 M1 驗收漏的 UI 環節)
- Ubuntu 端實機驗證 bootstrap-linux.sh
- 三方互相審閱(PM↔Design↔Architect 交叉 review)
- 使用者確認三份文件
M1 開發進度(第二階段)
| # | 任務 | 狀態 |
|---|---|---|
| M1-1 | repo 骨架初始化 | ✅ 完成(Review 通過) |
| M1-2 | 複製 server core(跳過 cluster/tunnel/flash/update) | ✅ 完成(Review 通過) |
| M1-3 | 改寫 main.go / config.go / router.go | ✅ 完成(Review 通過) |
| M1-4 | 複製 frontend | ✅ 完成 |
| M1-5 | build Go server binary | ✅ 完成(Review 通過) |
| M1-6 | 複製 server/data 預置模型 | ✅ 已於 M1-2 併入(8 個 .nef, 73MB) |
| M1-7 | 清理前端 cluster/relay/tunnel UI | ✅ 完成(Review 通過) |
| M1-8 | pnpm build 通過 | ✅ 已於 M1-7 併入驗收 |
| M1-9 | 複製 installer shell 改名 visiona-local | ✅ 完成(Review 通過) |
| M1-10 | 改寫 installer + Python 雙策略空殼 | ✅ 完成(Review 通過) |
| M1-11 | payload 打包 | ✅ 完成(103MB,含 server binary + 8 nef) |
| M1-12 | wails build + ad-hoc sign + dmgbuild | ✅ 完成(.dmg 70MB 產出) |
| M1-13 | 全新 mac 端到端驗證 | ✅ 完成(5 核心承諾全達成;2 P0 + 1 路徑 bug 已修復) |
第二輪產出(進行中)
- Architect:
/Users/jimchen/visionA/local-tool/.autoflow/04-architecture/design-doc.md(索引)TDD.md(索引)architecture-overview.mddependency-bundling.mdpackaging.mdbuild-pipeline.mdtray-and-lifecycle.mdi18n.mdrisks-and-mitigations.mdapi-endpoints.mdcode-reuse-plan.mdremoved-code.md
重要決策紀錄
來源與策略
- 參考原專案:
/Users/jimchen/Innovedus/edge-ai-platform - 程式碼策略:重新建立 local-tool,可從 edge-ai-platform 自由取用任何程式碼(不做 fork、不做 submodule)
- 產品名稱:visionA-local
- Bundle ID(暫定):
com.innovedus.visiona-local
產品定位
- 單機桌面應用,不需要 proxy / nginx / relay / tunnel
- Web UI 跑在 localhost(沿用原本 3721 埠或視情況調整)
- 必須能打包成 GUI 安裝檔,支援 macOS / Windows / Ubuntu
- 目標是「裝起來像一般 app」的體驗(類似 Docker Desktop / Ollama)
功能取捨(全照建議)
| 功能 | 決定 |
|---|---|
| 裝置管理(USB 連 Kneron) | ✅ 保留 |
| 攝影機串流(MJPEG + FFmpeg) | ✅ 保留 |
| 模型管理(上傳/切換 .nef) | ✅ 保留 |
| 推論引擎(分類/偵測/臉辨) | ✅ 保留 |
| Mock 模式 | ✅ 保留 |
| Tray(系統列常駐) | ❌ 砍(2026-04-11 改變:Q7 選關閉=結束後 tray 價值降低) |
| Cluster(多裝置叢集) | ❌ 砍 |
| Relay / Tunnel(遠端連線) | ❌ 砍 |
技術決策
- GUI 框架:Wails(沿用 edge-ai-platform 的
installer/) - 依賴打包:一鍵安裝所有依賴 — Python runtime + KneronPLUS SDK + ffmpeg + 預置模型 .nef 全部包進安裝檔,使用者不需要事先裝任何東西
- 前端清理:清掉 relay 模式切換、cluster 管理等 UI
原專案技術堆疊(沿用)
- 前端:Next.js 16 + React 19 + TypeScript + shadcn/Radix + Tailwind + Zustand
- 後端:Go 1.26 + Gin + go:embed
- 硬體:Python KneronPLUS SDK
- 儲存:本地 JSON + 記憶體(無 DB)
第四輪使用者決策(2026-04-11,三方交叉審閱後)
| # | 問題 | 決定 |
|---|---|---|
| R4-1 | Kneron 授權 | 繼續內嵌(不主動問 Kneron,B4 延續,發佈前 gate 維持) |
| R4-2 | MJPEG 延遲指標 | 首次 ≤250ms / 穩定後 ≤150ms |
| R4-3 | WCAG 2.2 AA | 不做(改為「盡力而為」,明確 scope 外) |
| R4-4 | 安裝時間 / RAM 指標 | 放寬:安裝上限 5 分鐘、Mock idle RAM ≤600MB |
| R4-5 | 資料目錄命名 | 全小寫 visiona-local(符合 Bundle ID + Linux 慣例) |
| R4-6 | 快捷鍵 | ⌘R → ⌘Shift+R;⌘Shift+W 取消(⌘4 已涵蓋) |
| R4-7 | 首次推論時間 AC | 拆為 首次 30s / 回訪 15s 兩級 |
| R4-8 | OS 通知策略 | 裝置連/斷 → App 內 toast;Server 崩潰 → shell out 原生通知 |
第三輪使用者決策(2026-04-11,三方第二輪文件後)
| # | 問題 | 決定 |
|---|---|---|
| Q-A | Tray 角色衝突(Q7 選關閉=結束後 tray 價值變低) | A3 砍掉 tray,省跨平台圖資產與 Wails tray 踩坑。從「保留功能」改為「不做」 |
| Q-B | Kneron 預置模型 re-distribution 授權 | B4:先假設可重新散布,開發時繼續內嵌,發佈前必須再確認(風險標記) |
| Q-C | M1 範圍 | C2 不接受「M1 先不清前端」:M1 就要把前端 cluster/relay UI 清乾淨,一次到位 |
| Q-D | vendor/ 目錄管理 | D2 不進 git,用 make vendor-sync 下載 |
| Q-E1 | macOS 資料目錄 | 用 ~/Library/Application Support/visionA-local/(OS 慣例) |
| Q-E2 | Workspace 提升為 sidebar 一級 | OK |
| Q-E3 | Settings「外觀」分頁取消,語言併入「一般」 | OK |
第二輪使用者決策(2026-04-11)
| # | 問題 | 決定 |
|---|---|---|
| Q1 | Python runtime 策略 | A(完全離線內嵌 python-build-standalone),同時保留 B(偵測系統 Python)作為 fallback 選項 |
| Q2 | 程式碼簽章 | C 都不買(內部工具接受警告) |
| Q3 | 最低 OS 版本 | 都最新兩版(macOS 14/15、Windows 10/11、Ubuntu 22.04/24.04) |
| Q4 | ARM 支援 | 三平台都只做 x86_64,之後有需求再加(使用者是 Intel Mac) |
| Q5 | 預置模型 | 全部打包(~73MB) |
| Q6 | Auto-update | 先不做 |
| Q7 | 視窗關閉行為 | B 傳統式(關閉 = 結束程式) |
| Q8 | 預設執行模式 | 直接真實硬體模式(不預設 Mock) |
| Q9 | 韌體燒錄 flash | B 砍掉 |
| Q10 | yt-dlp / media/url | A 保留(要打包 yt-dlp) |
| Q11 | Bundle ID | com.innovedus.visiona-local 確認 |
| Q12 | Telemetry / 崩潰回報 | 預設不做 |
| Q13 | 多語系 | 中英雙語 |
| Q14 | Logo / 品牌 | 先沿用 edge-ai-platform,之後有需要再換 |
| Q15 | 深色模式 | 跟隨系統 |
M1-10 留下的 M2/M1+ TODO(不阻斷 M1)
ensureBundledPython()實作(解壓 python-build-standalone、建 venv、離線 pip install wheels)— M2- Wails
/ipc/raiseendpoint(真正的 single-instance focus)— M1+ watchServer()健康偵測 goroutine(每 10s health check)— M1+isOurStaleServer/killByPort(stale process 清理)— M1+- Fatal 錯誤的原生對話框(目前只 emit event)— M1+
未解決問題
- Kneron 預置模型 re-distribution 授權(B4 決策):開發階段先假設可用,發佈前必須跟 Kneron 官方確認。若不允許需改為首次啟動線上下載,會破壞「完全離線」承諾。
- ffmpeg GPL 授權 release blocker(M6):macOS 上的 ffmpeg static build 全是 GPL,暫定用
VISIONA_ALLOW_GPL_FFMPEG=1放行,發佈前需法務 review 或改走自 build LGPL / 線上下載 / 砍 ffmpeg 三條路。 - 內部 Gitea Releases / GitHub Releases 基礎設施:發佈策略假設有此通路,待確認。
- CI runner 三平台是否齊備:macOS / Windows / Linux runner 狀況待確認。
- M1 驗收流程漏看 Wails 視窗內容:M1-13 當初是用瀏覽器連
http://localhost:3721/驗證 server 回應,沒真的開 Wails window 看 UI,導致 edge-ai-platform installer wizard 殘留一路混過 M1-M6 到 Windows 實機驗證才發現。後續 M 任務的驗收 checklist 必須強制「開 app window 確認主 UI 是 Next.js 而非 splash / wizard / 白畫面」。
第一輪三方分析產出(已完成)
- PM:
/Users/jimchen/visionA/local-tool/.autoflow/01-requirements/pm-analysis-round1.md - Design:
/Users/jimchen/visionA/local-tool/.autoflow/03-design/design-analysis-round1.md - Architect:
/Users/jimchen/visionA/local-tool/.autoflow/04-architecture/architect-analysis-round1.md