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>
29 KiB
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
- 本檔是「將來要做的驗證計畫」、不是驗證執行報告。執行階段由 testing + backend Agent 接手、結果回填到本檔 §8 與相關研究檔。
- 必須驗證的關鍵 unknown 共 10 項,分 3 大類:
- SDK API 行為(API 簽名 / .tar 支援 / chip enum 完整性)— 6 項
- KL630/KL730 連線行為(USB scan / connect / firmware load)— 3 項
- KneronPLUS wheel 版本相容性(既有 wheel 是否需升級 + 升級風險)— 1 項
- 驗證有兩個強度等級:
- 強驗證(有實機 KL630/KL730 dongle)— 涵蓋 10 項全部、結果可信
- 弱驗證(無實機、只查 SDK 文件 + wheel source)— 涵蓋 6 項(API 層)、剩 4 項(連線行為)只能靠文件推斷、留風險到 M9-9 開發階段
- 預估時間:強驗證 2 人天、弱驗證 1 人天
- 關鍵風險:拿不到 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_KL730enum? - 依賴實機:否(只需 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 的0x0200vs0x0720)? - 依賴實機:是(必須有 dongle)
- 影響:
_KNOWN_PRODUCTSmap 是否需擴展、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.gofirmware 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-2:wheel 內 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 層)
- 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)。
步驟:
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 是否存在
步驟:
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()→ 策略 Y(build time 解壓)
回填位置:本檔 §8.1、41-tar-firmware-handling.md §2.1 表格
A-5:update_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
預期結果:
- 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 範圍
步驟(弱驗證版本,無實機):
# 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 簽名變化
步驟(強驗證版本,有實機):
- 備份既有 wheel 安裝
- pip install warrenchen wheel 3.1.2
- 跑 visionA-local 既有 KL520 + KL720 完整 E2E:scan → connect → load firmware → inference
- 比對 inference 結果(用同一張圖、同一個 NEF、檢查 detection box 是否一致)
- 紀錄 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 已裝。
步驟:
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_PRODUCTSmap
回填位置:本檔 §8.2、40-b-phase §2.1
B-2:KL630/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-3:KL630/KL730 firmware 字串可能值
步驟:在 B-1 跑完已自然取得(dev.firmware 欄位)。額外重複測試不同 state:
- KL630 剛從盒子拿出來(未灌任何 firmware)→ 紀錄 firmware 字串
- KL630 跑過一次 inference 後(已 load firmware)→ 紀錄
- 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標準庫 + shelltar(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 的條件:
- KL630 / KL730 product_id 跟假設不同 → 更新
40-b-phase§2.1 + bridge.py 改動範圍 - KL630 / KL730 是 USB Boot 而非 flash-based → 整段 §5.2 推測重寫、
.tar處理流程設計重來 - SDK 完全沒有 .tar 支援 API → 策略 Z 永久排除、回到策略 Y、build script 必加
- 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 派工前必須先做的事
- 跟使用者確認硬體狀態:問「你或 Innovedus team 手上有 KL630 / KL730 dongle 嗎?多久能拿到?」
- 根據答案決定強 / 弱驗證:
- 有 → 強驗證、派 testing + backend
- 沒、3 週內能拿到 → 延後 M9-6、改先做選項 C mock(順手鋪路)
- 沒、無法取得 → 弱驗證、接受 M9-9 補強驗的風險
- 取得 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 更新 |