jim800121chen 46514d77d7 docs(local-tool): M9 — Kneron Dongle FW 偵測 + 升降版(A+B、翻案 R5-Q9)
L 級新功能、PRD/Design/TDD/ADR 三方協作 + 互審 + M9-6 SDK 雙驗證、總計 ~9000 行文件。

範圍:
- A 階段(MVP、5 人天):KL520 + KL720 自動升級 KDP1 → KDP2
- B 階段(10.5 人天):手動降版面向一般使用者 + KL630 / KL730 擴展
- 合計 15.5 人天、安裝包 +7MB(保守 bundle 策略)

關鍵決策:
- 翻案 R5-Q9(progress.md 第二輪使用者決策「韌體燒錄 flash → B 砍掉」)
- 跨平台用 KneronPLUS Python C API、不用 DFUT.exe
- 多版本目錄結構選 C metadata(firmware/<chip>/{version}/ + CURRENT_VERSION)
- Kneron firmware redistribution 授權與 R5-B4 預置模型同性質、發佈前評估

文件產出:
- PRD v2.2(PRD-v2.md 495 行 + features/feature-firmware-management.md 599 行)
- Design v2.2(firmware-management.md 948 行 + control-panel.md §6a graceful shutdown)
- TDD v2.2(v2/firmware-management.md 823 行 + ADR-001 218 行)
- 8 份 research(含 M9-6 弱驗證 + 強驗證、~3200 行)
- 3 份三方互審報告(PM/Design/Architect cross-review)

M9-6 強驗證重大發現(影響 B 階段):
- KL730 product_id 實際是 0x732(不是 0x0730)
- KL630/KL730 firmware 是 embedded Linux rootfs(不是 .bin、不同代設計)
- KneronPLUS Python 沒 update_kdp_firmware_from_files 公開 API、warrenchen 走 ctypes
- 不影響 A 階段、B 階段 M9-8 需 spike

下一步:派 backend M9-1 起跑(bridge.py handle_firmware_upgrade)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-25 07:40:56 +08:00

29 KiB
Raw Blame History

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 項)

每項 = 一個必須回答的具體問題。每項標:是否依賴實機、強度等級、後續決策影響。

類別 ASDK 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-2wheel 內 kp.ProductId.KP_DEVICE_KL630 / KL730 enum 是否存在

  • 問題:既有 wheel kp.ProductId.KP_DEVICE_KL630 / KL730 是否可 import、值是多少
  • 依賴實機:否
  • 影響A-2 若失敗 → 必須升級 wheel連 driver 認 chip 都做不到)

A-3kp.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-5update_kdp_firmware_from_files() 對 KL630/KL730 是否適用

  • 問題:把 KL630 device + KL630 .tar / .bin 餵進去、SDK 回什麼?是否有 chip-aware 內部 dispatch、還是 KL520/KL720 專用?
  • 依賴實機:部分(無實機只能查 source code 的 chip 分支邏輯)
  • 影響FW 升降版 API 選擇

A-6KneronPLUS wheel 升級對 KL520/KL720 既有行為的 regression 範圍

  • 問題:從目前 wheel → 3.1.2(或 latest有哪些 breaking change
  • 依賴實機:強驗證(升級後跑既有 E2E test弱驗證看 release notes / changelog
  • 影響:是否值得升 wheel、升級後 A 階段 KL520/KL720 是否需要回歸測試

類別 BKL630 / KL730 連線行為(需實機強驗證)

B-1KL630 / KL730 在 USB scan 時的 product_id

  • 問題:實機 kp.core.scan_devices() / pyusb scan 時KL630 dongle 的 product_id0x0630KL730 是 0x0730 嗎?是否有 legacy/new 雙版本(像 KL720 的 0x0200 vs 0x0720
  • 依賴實機:是(必須有 dongle
  • 影響_KNOWN_PRODUCTS map 是否需擴展、chipFromProductID() switch 是否要加額外 case

B-2KL630 / KL730 是否每次 connect 都要 load firmware

  • 問題:實機連續 connect 兩次、第二次是否需要重新 load firmwareKL520 要、KL720 不要)
  • 依賴實機:是
  • 影響connect 流程設計(速度 + 用量)、是否走 build time 解壓 vs runtime 解壓

B-3KL630 / 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。

步驟

# 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-2wheel 內 KL630/KL730 enum 存在驗證

前置A-1 已找到 wheel、Python 環境可 import kp

步驟

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 層)
  • BKL520/KL720 有、KL630/KL730 沒有 → 必須升級 wheel
  • Cimport kp 直接 import error → wheel 未安裝、A-1 結果有誤、回去查

回填位置:本檔 §8.1、影響 M9-7 決策

A-3load_firmware_from_file 對 .tar 行為

前置A-1 + A-2 完成、warrenchen .tar 檔已取得(在 /tmp/web_academy_prototype/local_service_win/firmware/KL630/kp_firmware.tar)。

步驟

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

預期結果三種

  • ASDK 接受 .tar、回 success → 策略 Z 可行
  • BSDK 報 KP_FW_INFO_ERR / 類似錯誤碼 → 策略 Y 必須走build time 解壓)
  • Csource 顯示函式內有 .endswith(".tar") 之類判斷 → 確認 SDK 內部分支邏輯

回填位置:本檔 §8.1、41-tar-firmware-handling.md §2.1 + §4.4

A-4load_firmware_from_tar / update_*_from_tar 是否存在

步驟

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 環境也能跑):

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() → 策略 Ybuild time 解壓)

回填位置:本檔 §8.1、41-tar-firmware-handling.md §2.1 表格

A-5update_kdp_firmware_from_files 對 KL630/KL730 chip dispatch

步驟

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

預期結果

  • Asource 內有 if chip == "KL630" 之類分支 → 適用、可直接用
  • Bsource 只處理 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-6wheel 升級對 KL520/KL720 regression 範圍

步驟(弱驗證版本,無實機):

# 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 完整 E2Escan → connect → load firmware → inference
  4. 比對 inference 結果(用同一張圖、同一個 NEF、檢查 detection box 是否一致)
  5. 紀錄 break point

預期結果

  • AAPI 簽名完全相容、inference 結果一致 → 升級安全
  • BAPI 簽名有 breaking change部分函式 rename / 參數順序變) → 升級需配合 bridge.py 更新
  • Cinference 結果不一致 → 升級風險高、需深查

回填位置:本檔 §8.1、新增風險紀錄到 R-FW-8

B-1KL630/KL730 USB scan product_id

前置:實機 KL630 + KL730 dongle 接上電腦、driver 已裝。

步驟

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

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-2KL630/KL730 每次 connect 都要 load firmware 嗎

前置B-1 完成、確認能識別 KL630/KL730。

步驟

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-3KL630/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/

步驟

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 tarmacOS / 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-2KneronPLUS 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-7B0 認 chip B-1 結果可能調整 chip 判斷邏輯、+0.1 天
M9-8.tar handling 高:策略 Y vs Z 完全不同實作、工時可能 ±0.5 天
M9-9connect + inference B-2 / B-3 結果決定 connect 流程設計
M9-10FW 升版擴 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-2KL630/KL730 enum 存在 未驗證
A-3load_firmware_from_file 對 .tar 行為 未驗證
A-4load_firmware_from_tar 是否存在 未驗證
A-5update_kdp_firmware_from_files 對 KL630/KL730 適用性 未驗證
A-6wheel 升級 regression 範圍 未驗證

8.2 B 類結果

項目 結果 證據 對下游決策影響
B-1KL630/KL730 product_id 未驗證
B-2KL630/KL730 是否每次 connect 重 load firmware 未驗證
B-3KL630/KL730 firmware 字串可能值 未驗證

8.3 C 類結果

項目 結果 證據 對下游決策影響
C-1.tar 內容 未驗證

8.4 整體結論(執行後填)

  • 策略 Y vs Z 選定:待驗證後填
  • wheel 升級決策:待驗證後填
  • B 階段啟動 go/no-go待驗證後填

9. 給 Orchestrator 的執行建議

9.1 何時派工

選項 AA 階段 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 階段同檔修改衝突(協調好就好)

選項 BA 階段 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 更新