# M9-6 SDK 驗證計畫書 > 對應 research index §50 > 範圍:B 階段啟動前的 KneronPLUS SDK + KL630/KL730 SDK 行為實機驗證計畫 > 撰寫日期:2026-05-24 > 限制:純 plan、不出 code、不執行驗證(驗證由 testing/backend 工程師執行) > 路徑使用相對路徑(相對於 `/Users/jimchen/visionA/local-tool/`) --- ## 0. TL;DR 1. 本檔是「**將來要做的驗證計畫**」、不是驗證執行報告。執行階段由 testing + backend Agent 接手、結果回填到本檔 §8 與相關研究檔。 2. 必須驗證的關鍵 unknown 共 **10 項**,分 3 大類: - **SDK API 行為**(API 簽名 / .tar 支援 / chip enum 完整性)— 6 項 - **KL630/KL730 連線行為**(USB scan / connect / firmware load)— 3 項 - **KneronPLUS wheel 版本相容性**(既有 wheel 是否需升級 + 升級風險)— 1 項 3. 驗證有兩個強度等級: - **強驗證**(有實機 KL630/KL730 dongle)— 涵蓋 10 項全部、結果可信 - **弱驗證**(無實機、只查 SDK 文件 + wheel source)— 涵蓋 6 項(API 層)、剩 4 項(連線行為)只能靠文件推斷、留風險到 M9-9 開發階段 4. 預估時間:強驗證 2 人天、弱驗證 1 人天 5. **關鍵風險**:拿不到 KL630/KL730 硬體 → 強驗證降級為弱、B 階段所有 milestone 都帶 SDK unknown 風險 --- ## 1. 為什麼需要 SDK 驗證 ### 1.1 前兩輪研究的 SDK unknown 清單 從 `40-b-phase-kl630-kl730-extension.md` §3.2 + `41-tar-firmware-handling.md` §2 + §5 整理: | 來源 | unknown | 影響範圍 | |------|---------|---------| | `40-b-phase` §3.2 row 1 | KL630 `connect_devices()` 是否與 KL520/KL720 共用簽名 | connect 流程設計 | | `40-b-phase` §3.2 row 2 | `load_firmware_from_file()` 對 KL630/KL730 是否仍接受兩個 .bin(解壓後) | .tar 處理策略選定(Y or Z)| | `40-b-phase` §3.2 row 3 | 是否有 `load_firmware_from_tar()` 之類新 API | 策略 Z 是否可行 | | `40-b-phase` §3.2 row 4 | `update_kdp_firmware_from_files()` 對 KL630/KL730 是否適用 | FW 升降版 API 選擇 | | `40-b-phase` §3.2 row 5 | KL630/KL730 是否仍有 Loader / KDP / KDP2 三 state | FW 偵測邏輯 | | `40-b-phase` §3.2 row 6 | KL630/KL730 是 flash-based 還是每次都要 load firmware | connect 速度設計 | | `40-b-phase` §3.2 row 7 | `generic_image_inference_send/receive` 對 KL630/KL730 是否一致 | inference 流程是否分支 | | `40-b-phase` §3.2 row 8 | KL630/KL730 firmware 字串可能值 | FW badge 顯示邏輯 | | `41-tar` §1.3 | .tar 內容(解壓後有哪些檔案、metadata) | bridge.py 解析邏輯 | | `41-tar` §2.3 | visionA-local 既有 KneronPLUS wheel 版本 vs 3.1.2 | wheel 升級決策 | ### 1.2 為什麼這些必驗、不能靠推測 每個 unknown 都有「假設錯了會炸」的後果: - API 簽名假設錯 → bridge.py 寫出來直接 import error / type error / runtime crash - .tar 處理策略選錯 → 安裝包大小 / build script 設計全錯、要從 M9-8 整段重做 - wheel 版本假設錯 → KL520/KL720 既有功能 regression、回頭重做 A 階段 → M9-6 是 B 階段 critical path、所有後續 milestone 都依賴它。 --- ## 2. 驗證目標清單(10 項) 每項 = 一個必須回答的具體問題。每項標:是否依賴實機、強度等級、後續決策影響。 ### 類別 A:SDK API 行為(弱驗證即可、查 wheel source / SDK 文件) #### A-1:既有 KneronPLUS wheel 版本是什麼 - **問題**:visionA-local repo 內目前用的 KneronPLUS wheel 是哪個版本?是否內含 `KP_DEVICE_KL630` / `KP_DEVICE_KL730` enum? - **依賴實機**:否(只需 Python 環境) - **影響**:決定要不要升級 wheel(升級會牽動 KL520/KL720 regression 風險) #### A-2:wheel 內 `kp.ProductId.KP_DEVICE_KL630` / `KL730` enum 是否存在 - **問題**:既有 wheel `kp.ProductId.KP_DEVICE_KL630` / `KL730` 是否可 import、值是多少 - **依賴實機**:否 - **影響**:A-2 若失敗 → 必須升級 wheel(連 driver 認 chip 都做不到) #### A-3:`kp.core.load_firmware_from_file()` 對 .tar 的行為 - **問題**:把 `.tar` 路徑當 `scpu_file` 參數餵進去、SDK 回什麼?接受、解析錯誤、還是 silent fail? - **依賴實機**:否(傳路徑、看 exception type) - **影響**:決定 .tar 處理策略(Y 解壓 or Z 直接餵) #### A-4:是否有 `load_firmware_from_tar()` / `update_*_from_tar()` 新 API - **問題**:wheel 內是否提供 .tar 專用 firmware load API?簽名為何? - **依賴實機**:否(grep wheel source) - **影響**:策略 Z 是否可行(最乾淨方案) #### A-5:`update_kdp_firmware_from_files()` 對 KL630/KL730 是否適用 - **問題**:把 KL630 device + KL630 .tar / .bin 餵進去、SDK 回什麼?是否有 chip-aware 內部 dispatch、還是 KL520/KL720 專用? - **依賴實機**:部分(無實機只能查 source code 的 chip 分支邏輯) - **影響**:FW 升降版 API 選擇 #### A-6:KneronPLUS wheel 升級對 KL520/KL720 既有行為的 regression 範圍 - **問題**:從目前 wheel → 3.1.2(或 latest)有哪些 breaking change? - **依賴實機**:強驗證(升級後跑既有 E2E test);弱驗證(看 release notes / changelog) - **影響**:是否值得升 wheel、升級後 A 階段 KL520/KL720 是否需要回歸測試 ### 類別 B:KL630 / KL730 連線行為(需實機強驗證) #### B-1:KL630 / KL730 在 USB scan 時的 product_id - **問題**:實機 `kp.core.scan_devices()` / pyusb scan 時,KL630 dongle 的 `product_id` 是 `0x0630` 嗎?KL730 是 `0x0730` 嗎?是否有 legacy/new 雙版本(像 KL720 的 `0x0200` vs `0x0720`)? - **依賴實機**:是(必須有 dongle) - **影響**:`_KNOWN_PRODUCTS` map 是否需擴展、`chipFromProductID()` switch 是否要加額外 case #### B-2:KL630 / KL730 是否每次 connect 都要 load firmware - **問題**:實機連續 connect 兩次、第二次是否需要重新 load firmware?(KL520 要、KL720 不要) - **依賴實機**:是 - **影響**:connect 流程設計(速度 + 用量)、是否走 build time 解壓 vs runtime 解壓 #### B-3:KL630 / KL730 firmware 字串可能值 - **問題**:實機 `scan_devices()` 回傳的 `device.firmware` 欄位字串是什麼?"KDP2" / "KDP3" / "Loader" / 其他?是否能透過此值區分「需要升級」vs「已 ready」? - **依賴實機**:是 - **影響**:FW badge UI 顯示邏輯、`detector.go` firmware state 判斷 ### 類別 C:.tar 檔案內容(無實機也能驗、純 tar -xf) #### C-1:.tar 內容實測 - **問題**:`tar -tvf kp_firmware.tar` / `tar -tvf kp_loader.tar` 內含哪些檔案?大小?是否有 manifest? - **依賴實機**:否(只需 warrenchen bundle 的 .tar 檔) - **影響**:bridge.py 解壓後檔案路徑解析邏輯、`_resolve_firmware_paths` 設計 --- ## 3. 各項驗證方法(執行 step-by-step) > **注意**:這節是給未來執行 M9-6 的 testing/backend 工程師看的、step 描述要可重複。 ### A-1:既有 wheel 版本查詢 **前置**:在 visionA-local repo 根目錄、Python 環境已 setup。 **步驟**: ```bash # Step 1: 找 KneronPLUS wheel 位置 find . -name "KneronPLUS*.whl" 2>/dev/null find . -name "kneronplus*.whl" 2>/dev/null # 若上述都沒結果、檢查是否 venv 內安裝 . server/scripts/venv/bin/activate 2>/dev/null && pip show kneronplus 2>/dev/null # 也檢查專案有沒有 vendored Python source find . -path "*/kp/__init__.py" -not -path "*/node_modules/*" 2>/dev/null ``` **預期結果三種**: - **A**:找到 `KneronPLUS-X.Y.Z-py3-none-any.whl` → 記錄版號 X.Y.Z - **B**:找到 installed package、`pip show` 回版本 → 記錄 - **C**:找不到 → wheel 是 lazy import 或 system-wide install、需查 `kneron_bridge.py` `_macos_preload_native_libs()` 內的 lib path 反推 wheel 位置 **回填位置**:本檔 §8.1、`41-tar-firmware-handling.md` §2.3 ### A-2:wheel 內 KL630/KL730 enum 存在驗證 **前置**:A-1 已找到 wheel、Python 環境可 `import kp`。 **步驟**: ```bash python3 -c " import kp print('KP_DEVICE_KL520:', getattr(kp.ProductId, 'KP_DEVICE_KL520', 'NOT FOUND')) print('KP_DEVICE_KL720:', getattr(kp.ProductId, 'KP_DEVICE_KL720', 'NOT FOUND')) print('KP_DEVICE_KL630:', getattr(kp.ProductId, 'KP_DEVICE_KL630', 'NOT FOUND')) print('KP_DEVICE_KL730:', getattr(kp.ProductId, 'KP_DEVICE_KL730', 'NOT FOUND')) print('KP_DEVICE_KL530:', getattr(kp.ProductId, 'KP_DEVICE_KL530', 'NOT FOUND')) " ``` **預期結果三種**: - **A**:四個都 print 出整數值 → 既有 wheel OK、不必升級(僅針對 enum 層) - **B**:KL520/KL720 有、KL630/KL730 沒有 → 必須升級 wheel - **C**:`import kp` 直接 import error → wheel 未安裝、A-1 結果有誤、回去查 **回填位置**:本檔 §8.1、影響 M9-7 決策 ### A-3:load_firmware_from_file 對 .tar 行為 **前置**:A-1 + A-2 完成、warrenchen .tar 檔已取得(在 `/tmp/web_academy_prototype/local_service_win/firmware/KL630/kp_firmware.tar`)。 **步驟**: ```bash python3 << 'EOF' import kp import sys # 試 connect KL630 dongle、若無實機跳過、改成 mock test tar_path = "/tmp/web_academy_prototype/local_service_win/firmware/KL630/kp_firmware.tar" # 情境 1:用實機(若有) try: descs = kp.core.scan_devices() kl630_port = None for i in range(descs.device_descriptor_number): dev = descs.device_descriptor_list[i] # 假設 KL630 product_id = 0x0630、若 B-1 驗證後值不同要修 if hex(dev.product_id) == "0x630": kl630_port = dev.usb_port_id print(f"KL630 found at port {kl630_port}") break if kl630_port: dg = kp.core.connect_devices([kl630_port]) # 試把 .tar 直接餵 try: ret = kp.core.load_firmware_from_file(dg, tar_path, "") print(f"load_firmware_from_file(.tar, '') = {ret}") except Exception as e: print(f"load_firmware_from_file(.tar, '') raised: {type(e).__name__}: {e}") # 試把 .tar 當 scpu + ncpu 同檔 try: ret = kp.core.load_firmware_from_file(dg, tar_path, tar_path) print(f"load_firmware_from_file(.tar, .tar) = {ret}") except Exception as e: print(f"load_firmware_from_file(.tar, .tar) raised: {type(e).__name__}: {e}") except Exception as e: print(f"No device, skip runtime test: {e}") # 情境 2:純靜態查 source(無實機也能跑) import inspect print("\nload_firmware_from_file source:") try: print(inspect.getsource(kp.core.load_firmware_from_file)) except Exception as e: print(f"Cannot get source: {e}") EOF ``` **預期結果三種**: - **A**:SDK 接受 .tar、回 success → 策略 Z 可行 - **B**:SDK 報 `KP_FW_INFO_ERR` / 類似錯誤碼 → 策略 Y 必須走(build time 解壓) - **C**:source 顯示函式內有 `.endswith(".tar")` 之類判斷 → 確認 SDK 內部分支邏輯 **回填位置**:本檔 §8.1、`41-tar-firmware-handling.md` §2.1 + §4.4 ### A-4:load_firmware_from_tar / update_*_from_tar 是否存在 **步驟**: ```bash python3 << 'EOF' import kp import kp.core # 列出 kp.core 所有 firmware-related 函式 for name in dir(kp.core): if any(k in name.lower() for k in ["firmware", "fw_", "load_fw", "update_kdp", "tar"]): print(f"kp.core.{name}") # 列出 kp 模組頂層 firmware-related for name in dir(kp): if any(k in name.lower() for k in ["firmware", "fw_", "tar"]): print(f"kp.{name}") EOF ``` **或解壓 wheel grep**(無 Python 環境也能跑): ```bash cd /tmp && unzip -o KneronPLUS-X.Y.Z-py3-none-any.whl -d kneron_plus_inspect/ grep -rn "load_firmware_from_tar\|update_kdp.*tar\|extract_tar\|from_tar" kneron_plus_inspect/kp/ grep -rn "^def \|^ def " kneron_plus_inspect/kp/core.py | grep -iE "fw|firmware|tar" ``` **預期結果**: - **A**:找到 `load_firmware_from_tar()` 或 `update_kdp2_firmware_from_tar()` → 策略 Z 確定可行 - **B**:找不到、只有既有 `load_firmware_from_file()` → 策略 Y(build time 解壓) **回填位置**:本檔 §8.1、`41-tar-firmware-handling.md` §2.1 表格 ### A-5:update_kdp_firmware_from_files 對 KL630/KL730 chip dispatch **步驟**: ```bash python3 << 'EOF' import kp.core import inspect # 看 update_kdp_firmware_from_files source 是否有 chip 判斷 try: src = inspect.getsource(kp.core.update_kdp_firmware_from_files) print(src) except Exception: pass # 列其他 update 系列函式 for name in dir(kp.core): if "update" in name.lower() and "fw" in name.lower(): print(name) EOF ``` **預期結果**: - **A**:source 內有 `if chip == "KL630"` 之類分支 → 適用、可直接用 - **B**:source 只處理 KL520/KL720 → 需找 `update_kdp2_firmware_*` 之類新 API - **C**:找不到對應 API → 須 fall back 用 `load_firmware_from_file` + 手動 reboot 流程 **回填位置**:本檔 §8.1、`40-b-phase` §3.2 row 4 ### A-6:wheel 升級對 KL520/KL720 regression 範圍 **步驟**(弱驗證版本,無實機): ```bash # Step 1: 取得 SDK changelog # 通常在 Kneron developer portal 或 wheel METADATA cd /tmp && unzip -o KneronPLUS-X.Y.Z-py3-none-any.whl -d wheel_old/ unzip -o /tmp/web_academy_prototype/local_service_win/KneronPLUS-3.1.2-py3-none-any.whl -d wheel_new/ diff -r wheel_old/kp/ wheel_new/kp/ | head -100 # 重點看 kp/core.py 和 kp/inference.py 的 API 簽名變化 ``` **步驟**(強驗證版本,有實機): 1. 備份既有 wheel 安裝 2. pip install warrenchen wheel 3.1.2 3. 跑 visionA-local 既有 KL520 + KL720 完整 E2E:scan → connect → load firmware → inference 4. 比對 inference 結果(用同一張圖、同一個 NEF、檢查 detection box 是否一致) 5. 紀錄 break point **預期結果**: - **A**:API 簽名完全相容、inference 結果一致 → 升級安全 - **B**:API 簽名有 breaking change(部分函式 rename / 參數順序變) → 升級需配合 bridge.py 更新 - **C**:inference 結果不一致 → 升級風險高、需深查 **回填位置**:本檔 §8.1、新增風險紀錄到 R-FW-8 ### B-1:KL630/KL730 USB scan product_id **前置**:實機 KL630 + KL730 dongle 接上電腦、driver 已裝。 **步驟**: ```bash python3 << 'EOF' import kp descs = kp.core.scan_devices() print(f"Total devices: {descs.device_descriptor_number}") for i in range(descs.device_descriptor_number): dev = descs.device_descriptor_list[i] print(f" device {i}:") print(f" product_id = {hex(dev.product_id)}") print(f" usb_port_id = {dev.usb_port_id}") print(f" firmware = {dev.firmware}") print(f" is_connectable = {dev.is_connectable}") print(f" kn_number = {dev.kn_number}") EOF ``` **同時用 pyusb 比對**(看 OS 層級看到什麼 product_id): ```bash python3 << 'EOF' import usb.core devs = usb.core.find(find_all=True, idVendor=0x3231) # Kneron VID for dev in devs: print(f"VID:PID = {hex(dev.idVendor)}:{hex(dev.idProduct)}") EOF ``` **預期結果**: - KL630 → product_id = `0x0630`、KL730 → `0x0730`、跟前兩輪研究假設一致 - 若有 legacy/new 雙版本(像 KL720 的 0x0200 vs 0x0720)→ 紀錄並更新 `_KNOWN_PRODUCTS` map **回填位置**:本檔 §8.2、`40-b-phase` §2.1 ### B-2:KL630/KL730 每次 connect 都要 load firmware 嗎 **前置**:B-1 完成、確認能識別 KL630/KL730。 **步驟**: ```bash python3 << 'EOF' import kp import time descs = kp.core.scan_devices() # 找 KL630(或 KL730) port_id = None for i in range(descs.device_descriptor_number): dev = descs.device_descriptor_list[i] if hex(dev.product_id) == "0x630": # KL630 port_id = dev.usb_port_id firmware_before = dev.firmware is_connectable_before = dev.is_connectable break if not port_id: print("No KL630 found") exit() print(f"Before connect: firmware={firmware_before}, is_connectable={is_connectable_before}") # 第一次 connect、不 load firmware dg1 = kp.core.connect_devices([port_id]) print(f"First connect OK, dg={dg1}") del dg1 time.sleep(2) # 重新 scan、看 firmware 字串是否變化 descs2 = kp.core.scan_devices() for i in range(descs2.device_descriptor_number): dev = descs2.device_descriptor_list[i] if dev.usb_port_id == port_id: print(f"After first connect: firmware={dev.firmware}, is_connectable={dev.is_connectable}") break # 第二次 connect、看是否仍能 inference(不重 load) dg2 = kp.core.connect_devices([port_id]) # 試跑 model load (用 KL630 sample NEF) # kp.core.load_model_from_file(dg2, "...sample.nef") # 觀察是否 OK EOF ``` **預期結果**: - **A**:第二次 connect 後直接能 inference、不用重 load firmware → flash-based、像 KL720 - **B**:第二次 connect 後 inference 失敗、需重新 `load_firmware_from_file()` → 像 KL520 **回填位置**:本檔 §8.2、`40-b-phase` §5.2 / §5.3 R-FW-10 ### B-3:KL630/KL730 firmware 字串可能值 **步驟**:在 B-1 跑完已自然取得(`dev.firmware` 欄位)。額外重複測試不同 state: 1. KL630 剛從盒子拿出來(未灌任何 firmware)→ 紀錄 firmware 字串 2. KL630 跑過一次 inference 後(已 load firmware)→ 紀錄 3. KL630 reboot 後 → 紀錄 **預期結果**: - 可能值:`""` / `"KDP"` / `"KDP2"` / `"KDP3"` / `"Loader"` / `"App"` / 其他 - 紀錄 chip × state 對照表 **回填位置**:本檔 §8.2、`40-b-phase` R-FW-10、`detector.go` firmware state map ### C-1:.tar 檔案內容實測 **前置**:warrenchen bundle 已 clone 到 `/tmp/web_academy_prototype/`。 **步驟**: ```bash cd /tmp/web_academy_prototype/local_service_win/firmware # KL630 echo "=== KL630 kp_firmware.tar ===" ls -lh KL630/kp_firmware.tar KL630/kp_loader.tar tar -tvf KL630/kp_firmware.tar tar -tvf KL630/kp_loader.tar # KL730 echo "=== KL730 kp_firmware.tar ===" ls -lh KL730/kp_firmware.tar KL730/kp_loader.tar tar -tvf KL730/kp_firmware.tar tar -tvf KL730/kp_loader.tar # 試解壓到 temp mkdir -p /tmp/kl630_extracted tar -xf KL630/kp_firmware.tar -C /tmp/kl630_extracted ls -lhR /tmp/kl630_extracted/ file /tmp/kl630_extracted/* # 看是否有 manifest / metadata for f in /tmp/kl630_extracted/*.json /tmp/kl630_extracted/*.txt /tmp/kl630_extracted/*.yml /tmp/kl630_extracted/*.yaml; do [ -f "$f" ] && echo "--- $f ---" && cat "$f" done ``` **預期結果**: - **A**:.tar 內含 `fw_scpu.bin` + `fw_ncpu.bin` + 可能 `manifest.json` → 策略 Y 解壓後拿 .bin 直餵 - **B**:.tar 內含其他結構(如 nested .tar / 加密檔) → 處理複雜度上升 **回填位置**:本檔 §8.3、`41-tar-firmware-handling.md` §1.3 --- ## 4. 驗證環境需求 ### 4.1 硬體 | 硬體 | 強驗證 | 弱驗證 | 取得來源 | |------|--------|--------|---------| | KL520 dongle | 可選(用於 wheel 升級回歸測試)| 不需 | 既有開發環境 | | KL720 dongle | 可選(同上)| 不需 | 既有開發環境 | | KL630 dongle | **必須 ≥1 顆** | 不需 | 問 Innovedus team / Kneron 借機 | | KL730 dongle | **必須 ≥1 顆** | 不需 | 問 Innovedus team / Kneron 借機 | | 跑驗證的主機 | macOS / Linux 至少 1 台、Windows 1 台(驗 driver install)| macOS 或 Linux 1 台即可 | 既有開發環境 | ### 4.2 軟體 - Python 3.10+(既有 venv 即可) - KneronPLUS Python wheel(既有 + warrenchen 3.1.2 兩版各一份) - KL630 / KL730 sample NEF 模型(從 Kneron sample 拿、用於 B-2 inference 測試) - 解壓工具:Python `tarfile` 標準庫 + shell `tar`(macOS / Linux 內建、Windows 10+ 內建) ### 4.3 SDK 文件 - KneronPLUS SDK Reference Manual PDF(從 Kneron developer portal 下載) - SDK changelog / release notes(決定升級的 breaking change 範圍) ### 4.4 平台覆蓋策略 **M9-6 階段**只驗 1 平台(推薦 macOS 或 Linux)、剩 2 平台留到 M9-13 整體三平台驗證跑。 理由:M9-6 主要驗 SDK API 行為(跨平台一致)、不是驗安裝 / driver / OS 整合(那是 M9-13)。 --- ## 5. 預估時間 ### 5.1 強驗證(有實機) | 階段 | 工時 | 累積 | |------|------|------| | 環境準備(取得硬體、裝 driver、setup Python) | 0.5 天 | 0.5 | | A 類驗證執行(A-1 ~ A-6)| 0.5 天 | 1.0 | | B 類驗證執行(B-1 ~ B-3)| 0.5 天 | 1.5 | | C 類驗證執行(C-1)| 0.1 天 | 1.6 | | 結果回填到本檔 §8 + 其他研究檔 | 0.4 天 | 2.0 | | **合計** | **2 人天** | | ### 5.2 弱驗證(無實機) | 階段 | 工時 | 累積 | |------|------|------| | 環境準備(裝 wheel、解壓 wheel source)| 0.2 天 | 0.2 | | A 類驗證執行(弱版本,無實機部分)| 0.3 天 | 0.5 | | B 類驗證跳過(只靠 SDK 文件推斷)| 0.2 天 | 0.7 | | C 類驗證執行 | 0.1 天 | 0.8 | | 結果回填 + 標註「需 M9-9 補強驗」| 0.2 天 | 1.0 | | **合計** | **1 人天** | | ### 5.3 預期 B 階段風險增量(採弱驗證的話) 如果 M9-6 走弱驗證、B-1 / B-2 / B-3 留到 M9-9 開發階段才實機驗: - M9-9 工時可能從 2 天 → 3 天(多 1 天驗 SDK 行為 + 修 bridge.py) - M9-13 三平台驗證可能多發現 1-2 個原本以為 work 的 case 實際不 work → **強烈建議走強驗證**、即使要等硬體到位。 --- ## 6. 風險 ### R-VAL-1:拿不到 KL630 / KL730 硬體(高度風險) **情境**:Innovedus / Kneron 沒法提供 dongle、或要等好幾週。 **緩解選項**: - **選項 A**:降級為弱驗證、B 階段啟動時 SDK unknown 帶到 M9-9 - **選項 B**:延後 B 階段啟動、等硬體到位(不影響 A 階段 MVP) - **選項 C**:先做 mock 驗證(建 mock SDK、用 monkey patch 假裝 KL630 device)、等實機到再覆驗 **建議**:選項 B(延後 B 階段)+ 順手做選項 C(建 mock 為將來測試鋪路) ### R-VAL-2:KneronPLUS wheel 不支援 KL630/KL730(中度) **情境**:A-2 驗證結果是 "B"(既有 wheel 沒有 KL630/KL730 enum)。 **緩解**: - 升級 wheel 到 warrenchen 3.1.2 或更新版 - A-6 評估 regression 範圍、必要時跑完整 KL520/KL720 回歸測試 - 預留 0.5-1 人天到 M9-7 做 wheel 升級 + regression ### R-VAL-3:驗證結果跟前兩輪研究假設不同(中度) **情境**:例如 B-1 發現 KL630 product_id 不是 `0x0630`、是 legacy + new 雙 ID。 **觸發重大調整 plan 的條件**: 1. KL630 / KL730 product_id 跟假設不同 → 更新 `40-b-phase` §2.1 + bridge.py 改動範圍 2. KL630 / KL730 是 USB Boot 而非 flash-based → 整段 §5.2 推測重寫、`.tar` 處理流程設計重來 3. SDK 完全沒有 .tar 支援 API → 策略 Z 永久排除、回到策略 Y、build script 必加 4. wheel 升級對 KL520 regression > 30% → 不升級、找其他方案(可能要找 Kneron 要 dev 版) 每個觸發條件對應的 plan 重做工時估算: - 觸發 1 → 0.2 天重寫 + M9-7 多 0.3 天 - 觸發 2 → 1 天重寫研究檔 + M9-8/M9-9 各多 0.5 天 - 觸發 3 → 不影響(策略選定即可) - 觸發 4 → 1-2 天找替代方案 ### R-VAL-4:硬體環境不穩、間歇性失敗(低度) **情境**:USB 接觸不良、dongle 過熱、driver 偶發崩潰。 **緩解**: - 每個 B 類驗證重複 3 次、取一致結果 - 紀錄不一致 case、單獨追 --- ## 7. 驗證完成的下游影響 ### 7.1 既有研究檔需要更新 | 檔案 | 章節 | 更新內容 | |------|------|---------| | `40-b-phase-kl630-kl730-extension.md` | §3.2 表格 | 填入「實測值」column | | `40-b-phase-kl630-kl730-extension.md` | §5.2 | KL630/KL730 推測段落改成「驗證結果」 | | `40-b-phase-kl630-kl730-extension.md` | §7 | inference 流程驗證 | | `40-b-phase-kl630-kl730-extension.md` | R-FW-8 / R-FW-10 | 風險紀錄狀態更新 | | `41-tar-firmware-handling.md` | §1.3 | .tar 內容實測結果 | | `41-tar-firmware-handling.md` | §2.1 / §2.2 / §2.3 | wheel 版本 + API 驗證結果 | | `41-tar-firmware-handling.md` | §3.3 | .tar 大小實測 | | `41-tar-firmware-handling.md` | §4.4 | 策略選定(Y or Z) | | `41-tar-firmware-handling.md` | §5 | 驗證計畫狀態改「已完成」+ 結果 | ### 7.2 milestone 重排可能性 | milestone | 受 M9-6 結果影響的程度 | |-----------|---------------------| | M9-7(B0 認 chip) | 低:B-1 結果可能調整 chip 判斷邏輯、+0.1 天 | | M9-8(.tar handling) | 高:策略 Y vs Z 完全不同實作、工時可能 ±0.5 天 | | M9-9(connect + inference) | 中:B-2 / B-3 結果決定 connect 流程設計 | | M9-10(FW 升版擴 KL630/KL730) | 中:A-5 結果決定用哪個 API | | M9-11(多版本) | 低 | | M9-12(降版 UI) | 低 | | M9-13(三平台驗證) | 中:若驗證發現新問題、增加 case 數 | ### 7.3 TDD v2.2 firmware-management.md 影響 從 `30-integration-plan.md` 已標 firmware-management 章節範圍。M9-6 結果可能影響: - §「SDK API 對照表」需填實測值 - §「KL630/KL730 連線流程」需確認 flash-based vs USB Boot - §「.tar 處理策略」需選定 Y or Z - §「KneronPLUS wheel 升級需求」需填升級決策 → **TDD v2.2 firmware-management.md 應該等 M9-6 完成再 finalize**、或 M9-6 結果作為 v2.2 → v2.3 的 update trigger。 --- ## 8. 驗證結果填空區(執行後填) > 本節是執行 M9-6 的工程師填寫的、現階段空白。 ### 8.1 A 類結果 | 項目 | 結果 | 證據 / 紀錄路徑 | 對下游決策影響 | |------|------|---------------|--------------| | A-1:既有 wheel 版本 | _未驗證_ | | | | A-2:KL630/KL730 enum 存在 | _未驗證_ | | | | A-3:load_firmware_from_file 對 .tar 行為 | _未驗證_ | | | | A-4:load_firmware_from_tar 是否存在 | _未驗證_ | | | | A-5:update_kdp_firmware_from_files 對 KL630/KL730 適用性 | _未驗證_ | | | | A-6:wheel 升級 regression 範圍 | _未驗證_ | | | ### 8.2 B 類結果 | 項目 | 結果 | 證據 | 對下游決策影響 | |------|------|------|--------------| | B-1:KL630/KL730 product_id | _未驗證_ | | | | B-2:KL630/KL730 是否每次 connect 重 load firmware | _未驗證_ | | | | B-3:KL630/KL730 firmware 字串可能值 | _未驗證_ | | | ### 8.3 C 類結果 | 項目 | 結果 | 證據 | 對下游決策影響 | |------|------|------|--------------| | C-1:.tar 內容 | _未驗證_ | | | ### 8.4 整體結論(執行後填) - 策略 Y vs Z 選定:_待驗證後填_ - wheel 升級決策:_待驗證後填_ - B 階段啟動 go/no-go:_待驗證後填_ --- ## 9. 給 Orchestrator 的執行建議 ### 9.1 何時派工 **選項 A:A 階段 MVP 同步起跑**(使用者目前決策) - M9-6 與 M9-1 ~ M9-5 平行 - 派 testing/backend Agent 在 A 階段任何時點啟動 M9-6(推薦 A 階段 50% 進度時) - M9-6 完成後 B 階段才能啟動、不卡 A 階段 - 風險:A 階段也在動 bridge.py、M9-6 可能跟 A 階段同檔修改衝突(協調好就好) **選項 B:A 階段 MVP 完成後啟動**(原計畫) - M9-6 + A 階段 5 人天 + B 階段 10.5 人天 = 序列 - 簡單、無衝突 - 風險:B 階段啟動延後 5 人天 **建議**:選 A、但安排 M9-6 在 A 階段 M9-3 或 M9-4 完成後啟動(bridge.py 大改動已完成)、避開檔案衝突。 ### 9.2 派工 Agent 選擇 **強驗證階段**: - 主要:testing Agent(驗證執行 + 結果紀錄是專業) - 配合:backend Agent(讀 SDK source code + 寫驗證 script 偏 backend 領域) - 推薦:testing 主派、backend 顧問 **弱驗證階段**(若無實機): - 主要:backend Agent(純查 source + 文件) - testing 可不參與 ### 9.3 派工前必須先做的事 1. **跟使用者確認硬體狀態**:問「你或 Innovedus team 手上有 KL630 / KL730 dongle 嗎?多久能拿到?」 2. **根據答案決定強 / 弱驗證**: - 有 → 強驗證、派 testing + backend - 沒、3 週內能拿到 → 延後 M9-6、改先做選項 C mock(順手鋪路) - 沒、無法取得 → 弱驗證、接受 M9-9 補強驗的風險 3. **取得 KneronPLUS SDK Reference Manual PDF**:問使用者 / 從 Kneron developer portal 下載、放到 `.autoflow/04-architecture/research-kl520-fw-management/refs/` 供工程師查 ### 9.4 派工 prompt 模板(給 Orchestrator 用) ``` 路徑資訊: - 你的角色定義:(對應 agent CLAUDE.md 絕對路徑) - 專案目錄:當前工作目錄 - 本任務 plan:`.autoflow/04-architecture/research-kl520-fw-management/50-m9-6-sdk-validation.md` - 結果回填到本檔 §8.1 / §8.2 / §8.3 任務:執行 M9-6 SDK 驗證(強驗證版本) 範圍:本檔 §2 列出的 10 個驗證項目、按 §3 的 step 執行 產出: 1. 本檔 §8 填空區填實測結果 2. 更新 §7.1 列的下游研究檔(標明「本次更新」) 3. 結果摘要丟給 Orchestrator、附 go/no-go 建議 不要做: - 改 bridge.py / driver code(驗證 only、不寫產品 code) - 改 TDD v2.2 firmware-management.md(那是 architect 範圍、本任務只回填到研究檔) ``` --- ## 10. 與其他研究檔的關係 | 連結 | 引用內容 | |------|---------| | `40-b-phase-kl630-kl730-extension.md` §3.2 | 本檔 §1.1 / §2 類別 A 大部分項目來源 | | `40-b-phase-kl630-kl730-extension.md` §5.2 / R-FW-10 | 本檔 §2 類別 B(連線行為驗證) | | `40-b-phase-kl630-kl730-extension.md` M9-6 段落 | 本檔是 M9-6 的詳細展開 | | `41-tar-firmware-handling.md` §1.3 | 本檔 §2 C-1 來源 | | `41-tar-firmware-handling.md` §2 | 本檔 §2 類別 A row A-3 / A-4 來源 | | `41-tar-firmware-handling.md` §5 | 本檔取代之前的 「待 M9-6 驗證」placeholder、§5 升級為 reference 本檔 | | `30-integration-plan.md` 階段 B 評估 | M9-6 結果回填觸發 TDD v2.2 firmware-management.md 更新 |