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

333 lines
24 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# M9-6 弱驗證結果(不含實機)
> 對應 `50-m9-6-sdk-validation.md` 的弱驗證執行
> 執行日期2026-05-24
> 執行者Architect Agent
> 路徑使用相對路徑(相對於 `/Users/jimchen/visionA/local-tool/`
---
## 環境
- **執行平台**macOS / sandboxed Architect Agent context無 Bash tool、無實機 dongle
- **執行限制**
- 不能解壓 wheel binary沒 Bash / `unzip` 可用、Read 對 deflate-compressed zip 內容只看到亂碼)
- 不能跑 Python REPL 確認 enum 值
- 不能解壓 `.tar` 看內容
- 不能 ssh 到實機
- **可用證據來源**
1. warrenchen prototype`/tmp/web_academy_prototype/`)的 Python source code
2. visionA-local 既有 `server/scripts/kneron_bridge.py`(看我們現在用了哪些 kp API
3. 既有研究檔 §00-§42
4. warrenchen bundled wheel filename pattern`KneronPLUS-3.1.2-py3-none-any.whl`
5. 既有 visionA-local wheel`KneronPLUS-2.0.0-py3-none-any.whl`macOS/Linux+ `KneronPLUS-3.1.2-py3-none-any.whl`Windows—— **wheel 版本三平台不一致**(重要發現)
---
## 結論TL;DR
1. **KneronPLUS 3.1.2 確認支援 KL630/KL730 enum**——warrenchen `main.py` L433-447 直接用 `kp.ProductId.KP_DEVICE_KL630/KL730/KL830`、運作中、enum 存在無疑。
2. **`update_kdp_firmware_from_files` API 在 KneronPLUS 3.1.2 存在且 warrenchen 已使用**——`update_kl720_firmware.py``legacy_plus121_runner.py` 兩個檔案大量使用 `lib.kp_update_kdp_firmware_from_files(dg, scpu, ncpu, auto_reboot)`。這是 KDP1 → KDP2 升版flash 寫入)的關鍵 API。
3. **`connect_devices_with_magic_pass` 概念存在、實際 API 是 `kp_connect_devices` + `KDP_MAGIC_CONNECTION_PASS=0x1FF55B4F` 狀態碼**——warrenchen 用此 magic value 繞過 KDP1 firmware 檢查、連到 legacy device、再寫 flash。這是 ctypes-level call、Python 層 `kp.core.connect_devices_without_check` 可能是同一 API 的 wrapper待強驗證確認
4. **`load_firmware_from_file` 只接受兩個 .bin 路徑scpu, ncpu、不接受 .tar**——warrenchen `FirmwareLoadRequest` schema 強證據:`scpu_path: str` + `ncpu_path: str`、無 `tar_path` 欄位。**策略 Z直接餵 .tar 給 SDK不可行**。
5. **沒有 `load_firmware_from_tar` / `update_kdp_firmware_from_tar` API**——warrenchen 完全沒有用、且若存在會出現在 `FirmwareLoadRequest``legacy_plus121_runner.py`。**策略 Ybuild time 解壓 .tar 找 .bin是唯一可行解**。
6. **warrenchen 對 KL630/KL730 的 firmware 升降版完全沒實作**——只有 KL520 + KL720 兩個 chip-specific endpoint`/firmware/legacy-upgrade/kl520` + `/firmware/legacy-upgrade/kl720`、KL630/KL730 沒有對應 endpoint。**這是設計 gap、不是 SDK 限制**。意味我們設計 A 階段的 `handle_firmware_upgrade` for KL630/KL730 時、沒有 reference 實作可抄、要自己根據 KneronPLUS SDK 推。
7. **重大發現visionA-local wheel 三平台版本不一致**——macOS/Linux 是 `KneronPLUS-2.0.0`、Windows 是 `KneronPLUS-3.1.2`。**2.0.0 是否含 `KP_DEVICE_KL630/KL730` enum 無法靜態確認**——`KP_DEVICE_KL720_LEGACY` 在 3.1.2 確認存在warrenchen L432但 2.0.0 不確定。**強驗證必跑**:在 macOS + Linux 上實際 `import kp; print(kp.ProductId.KP_DEVICE_KL630)` 看是否存在。
8. **PRD AC-FW-3.5KL630/KL730 升降版)的可行性結論**
- **理論上可行**SDK API 都在、enum 都在、`update_kdp_firmware_from_files` 對所有 chip 通用)
- **但弱驗證無法 100% 證明對 KL630/KL730 適用**——`update_kdp_firmware_from_files` 是否分支判斷 chip、KL630/KL730 是否走同一條 flash 寫入路徑、必須實機 confirm
- **建議**A 階段不開 KL630/KL730 升降版PRD AC-FW-3.5 暫降為 B 階段功能或標 "Tentative"、B 階段 M9-9 / M9-10 啟動時實機強驗
---
## Unknown 對照表
對應 `50-m9-6-sdk-validation.md` §2 的 10 個驗證項目:
| # | 類別 | Unknown | 弱驗證結果 | 仍需強驗證? | 影響 |
|---|------|---------|-----------|------------|------|
| A-1 | A | 既有 wheel 版本 | **三平台不一致**macOS/Linux 2.0.0、Windows 3.1.2(從 `visiona-local/wheels/*` glob 結果直接確認) | N已從檔名確認版本 | TDD §「KneronPLUS wheel 升級」必須記錄三平台不一致、考量是否統一升級到 3.1.2 |
| A-2 | A | wheel 內 `KP_DEVICE_KL630/KL730` enum | **3.1.2 確認有**warrenchen `main.py` L433-447 使用中);**2.0.0 待 Y**——靜態無法確認,需在 macOS/Linux 跑 `python3 -c "import kp; print(kp.ProductId.KP_DEVICE_KL630)"` | Y對 2.0.0 | 若 2.0.0 沒有 enum → 必須在 macOS/Linux 升級 wheel 到 3.1.2(會引入 KL520/KL720 regression 風險) |
| A-3 | A | `load_firmware_from_file` 對 .tar 行為 | **不接受 .tar、只接受兩個 .bin 路徑**warrenchen `FirmwareLoadRequest` schema = `scpu_path: str` + `ncpu_path: str` 強證據;`legacy_plus121_runner.py` L44-45 `lib.kp_load_firmware_from_file.argtypes = [c_void_p, c_char_p, c_char_p]`、兩個 c_char_p 對應兩個檔案) | Nschema 與 ctypes 簽名已強證據) | **策略 Z 確定不可行、必走策略 Y**build time 解壓 .tarTDD §「.tar firmware 處理」改為策略 Y 唯一方案、`_resolve_firmware_paths` 設計需走 `extracted/fw_scpu.bin` 路徑 |
| A-4 | A | `load_firmware_from_tar` / `update_*_from_tar` 是否存在 | **不存在**warrenchen 完全沒用、若存在會出現在 `FirmwareLoadRequest``legacy_plus121_runner.py`warrenchen 對 KL630/KL730 .tar 也沒有特別處理 endpoint | N負面證據強 | 同 A-3、策略 Z 排除 |
| A-5 | A | `update_kdp_firmware_from_files` 對 KL630/KL730 適用性 | **API 在 3.1.2 確認存在、簽名為 `(dg, scpu_path, ncpu_path, auto_reboot_bool)`**warrenchen `update_kl720_firmware.py` L110-120 與 `legacy_plus121_runner.py` L46-47 都明示);但**對 KL630/KL730 是否走同一條 flash 寫入路徑、無從靜態判斷**——warrenchen 對 KL630/KL730 完全沒用此 API沒有對應 endpoint | Y高度需要 | A 階段 KL630/KL730 升降版PRD AC-FW-3.5暫排除B 階段 M9-10 啟動前實機強驗、決定走 `update_kdp_firmware_from_files` 還是要找新 API |
| A-6 | A | wheel 升級對 KL520/KL720 regression 範圍 | **wheel 2.0.0 → 3.1.2 跨主版本、breaking change 風險高**——但無法靜態查 changelog沒 Kneron 官方文件 access既有 visionA-local kneron_bridge.py 用的 APIscan_devices、connect_devices、load_firmware_from_file、reset_device、load_model_from_file、generic_image_inference_send/receive、ChannelOrdering、GenericImageInferenceDescriptor、ImageFormat、ResetMode**這些 API 全部在 warrenchen 3.1.2 程式碼也有使用**(即 3.1.2 仍然支援)→ **可能可升級而不破壞既有 KL520/KL720** | Y必須三平台跑 E2E | 升 wheel 風險可控API 介面相容性看起來高);但必須 M9-13 三平台跑 KL520+KL720 完整 E2E 才能確定 |
| B-1 | B | KL630/KL730 USB scan product_id | **仍需實機**——0x0630/0x0730 是「研究階段假設」(從 visionA-local + warrenchen edge-ai 兩端 `_KNOWN_PRODUCTS` map 都這樣寫、但這些 map 是寫程式人猜的、warrenchen LocalAPI 程式碼**不直接用 product_id hex、而是用 `kp.ProductId.KP_DEVICE_KL630` enum 物件** | Y必須有實機 dongle | A/B 階段 driver `_KNOWN_PRODUCTS` map 維持 0x0630/0x0730 假設、但 M9-9 實機驗證時若不符要立刻調整 |
| B-2 | B | KL630/KL730 是否每次 connect 都要 load firmware | **仍需實機**——warrenchen 完全沒對 KL630/KL730 寫 connect/firmware load 流程、無 referenceKL520 是「USB Boot 必載」、KL720 是「flash-based 不載」、KL630/KL730 推測「flash-based 不載」(同新世代 SDK packaging 風格)但**僅推測** | Y | M9-9 啟動時實機跑「連續 connect 兩次、看第二次需不需要重 load」 |
| B-3 | B | KL630/KL730 firmware 字串可能值 | **仍需實機**——warrenchen 沒任何 KL630/KL730 firmware 字串紀錄KL520/KL720 我們既有觀察值是 `"KDP"` / `"KDP2"` / `"Loader"` / `""` 等 | Y | M9-9 實機 scan_devices() 直接看 `dev.firmware` 欄位 |
| C-1 | C | .tar 檔案內容 | **無法弱驗證**——`.tar` 是 binary、Grep tool 對 binary 跳過、無 Bash 跑 `tar -tvf`;唯一資訊:檔名 `kp_firmware.tar` + `kp_loader.tar`、warrenchen 對 .tar 內容沒留下 inspect 結果 | Y執行 `tar -tvf` 即可、無需實機) | M9-8 啟動前用 Bash 跑一次 `tar -tvf` 即解;不阻塞 A 階段任何工作 |
**統計**
- A 類 6 項 → 4 項弱驗證有答案、2 項需強驗證A-2 對 2.0.0、A-5 對 KL630/KL730 適用性、A-6 升 wheel regression
- B 類 3 項 → 0 項弱驗證有答案、3 項全需強驗證(必有實機)
- C 類 1 項 → 弱驗證可解但需 BashArchitect Agent 限制、移交 backend agent 5 分鐘可完成)
---
## 重點發現
### 發現 1KneronPLUS 3.1.2 enum 列表(從 warrenchen `main.py` L427-447 直接讀)
```python
KP_DEVICE_KL520
KP_DEVICE_KL720 # 0x0720 (KDP2 新版)
KP_DEVICE_KL720_LEGACY # 0x0200 (KDP1 老版、需走 magic pass)
KP_DEVICE_KL630
KP_DEVICE_KL730
KP_DEVICE_KL830 # 多一個未在 visionA-local 研究範圍的 chip
```
**意涵**
- KL720 有兩個 enum value`KL720` 對應 KDP2 / `KL720_LEGACY` 對應 KDP1、跟我們既有 visionA-local 認知一致
- **KL630/KL730 各只有一個 enum**——支持「KL630/KL730 沒有 legacy/new 雙版本」的假設(前一輪研究 §5.2 推測)
- **KL830 存在於 SDK 但 warrenchen 沒實作**——可能是更新一代的 chip、與本研究範圍無關
### 發現 2`update_kdp_firmware_from_files` 完整簽名(從 `legacy_plus121_runner.py` L46-47 + `update_kl720_firmware.py` L110-120
```python
# ctypes 層級簽名
lib.kp_update_kdp_firmware_from_files.argtypes = [
ctypes.c_void_p, # device_group handle
ctypes.c_char_p, # scpu_path (or None)
ctypes.c_char_p, # ncpu_path (or None)
ctypes.c_bool, # auto_reboot
]
lib.kp_update_kdp_firmware_from_files.restype = ctypes.c_int # 0 = success
# 用法 1先 flash SCPU不 reboot
ret = lib.kp_update_kdp_firmware_from_files(dg, scpu_path.encode("utf-8"), None, False)
# 手動 reset + reconnect
lib.kp_reset_device(dg, 0) # KP_RESET_REBOOT = 0
# 用法 2再 flash NCPU
ret = lib.kp_update_kdp_firmware_from_files(dg, None, ncpu_path.encode("utf-8"), False)
# 用法 3一次 flash 兩個 + auto rebootlegacy_plus121_runner.py L233 走這條)
ret = lib.kp_update_kdp_firmware_from_files(dg, loader_path.encode("utf-8"), None, True)
```
**意涵**
- API 支援獨立 flash SCPU 或 NCPU其中一個 path 傳 None
- `auto_reboot=True` 由 SDK 自己 reset device、caller 不需要再 `reset_device`、但接下來 `disconnect_devices` 可能會回 non-zeroUSB re-enumeration、warrenchen `legacy_plus121_runner.py` L273-277 明示這個情況)
- **Python wrapper `kp.core.update_kdp_firmware_from_files` 是否存在 / 簽名相同**——warrenchen 全部用 ctypes direct call、**沒用 Python wrapper**。這暗示 Python wrapper 可能不存在、或存在但 warrenchen 故意繞過(保有更多 error code 控制)
### 發現 3`KDP_MAGIC_CONNECTION_PASS = 0x1FF55B4F`(從 `update_kl720_firmware.py` L31 + `legacy_plus121_runner.py` L12
```python
KDP_MAGIC_CONNECTION_PASS = 0x1FF55B4F # = 536173391 decimal
# 連到 KDP1 legacy device 的方式(繞過 firmware version check
port_ids = (ctypes.c_int * 1)(port_id)
status = ctypes.c_int(KDP_MAGIC_CONNECTION_PASS)
dg = lib.kp_connect_devices(1, port_ids, ctypes.byref(status))
# status.value 之後會被 SDK 改寫成實際的 connect result code
```
**意涵**
- `kp_connect_devices` 的第三個參數status pointer有**雙向用途**caller 傳入 magic value、SDK 寫回 result code
- visionA-local 既有 bridge.py 用 `kp.core.connect_devices_without_check` 走 Python wrapper不需直接操作 magic——**這兩個 API 可能是同件事的兩種 binding**Python wrapper 內部就傳 magic value
- B 階段擴 KL630/KL730 時、如果碰到「old firmware 連不上」、需要 magic pass、可以複製 warrenchen 這個 pattern
### 發現 4`FirmwareLoadRequest` schema 證明 `.tar` 不被 SDK 接受
```python
# main.py L169-171
class FirmwareLoadRequest(BaseModel):
scpu_path: str
ncpu_path: str
```
**意涵**
- warrenchen 對外暴露的 firmware load API 強制要求兩個 .bin 路徑
- 若 SDK 接受 .tar、warrenchen 早該開 `tar_path: Optional[str]` 欄位
- 這個 schema 是 warrenchen 對 SDK 行為的最終共識——**.tar 不能直接餵、必須先解壓**
### 發現 5warrenchen 沒有 `/firmware/legacy-upgrade/kl630` 或 `kl730` endpoint
```python
# main.py 全部 firmware endpoint
@app.post("/firmware/load") # genericcaller 自己給 path
@app.post("/firmware/legacy-plus121/load") # KL720 KDP1 → KDP2 RAM-based
@app.post("/firmware/legacy-upgrade/kl520") # KL520 DFUT 路徑
@app.post("/firmware/legacy-upgrade/kl720") # KL720 DFUT 路徑
# ❌ 沒有 legacy-upgrade/kl630
# ❌ 沒有 legacy-upgrade/kl730
```
**意涵**
- warrenchen 對 KL630/KL730 升降版的設計 gap**不是 SDK 限制、是 warrenchen 沒做**
- 我們做 A 階段PRD AC-FW-3.5)時、不能直接抄 warrenchen 模式——要自己設計 KL630/KL730 升降版流程
- 對 PRD 影響AC-FW-3.5KL630/KL730 升降版)的**參考實作不存在**、設計工時要拉高M9-10 原估 1 人天可能不夠)
### 發現 6visionA-local wheel 三平台版本不一致
```
visiona-local/wheels/macos/KneronPLUS-2.0.0-py3-none-any.whl
visiona-local/wheels/linux/KneronPLUS-2.0.0-py3-none-any.whl
visiona-local/wheels/windows/KneronPLUS-3.1.2-py3-none-any.whl
```
**意涵**
- 目前 visionA-local 在三平台跑的 KneronPLUS API 行為**可能不一致**API 跨主版本可能有 breaking change
- 既有 KL520/KL720 在三平台都能 work 的事實 → 既有 bridge.py 用的 API subset 在 2.0.0 和 3.1.2 都存在
- **但 KL630/KL730 enum 在 2.0.0 是否存在無法靜態確認**
- A 階段PRD AC-FW-3.5)若要在 macOS + Linux 也支援 KL630/KL730 升降版、**必須先升級 macOS/Linux wheel 到 3.1.2**——這會引入 KL520/KL720 regression 風險、必須 M9-13 三平台 E2E 跑過才放心
- **PRD AC-FW-3.5 對三平台一致性的影響**A 階段若維持「只支援 KL520+KL720」、wheel 三平台不一致可暫不處理A 階段若要加 KL630/KL730、wheel 升級是強制前提
### 發現 7既有 visionA-local bridge.py 對 `load_firmware_from_file` 的使用模式
```python
# server/scripts/kneron_bridge.py L760-762 (KL720 KDP1 → load KDP2 to RAM)
kp.core.load_firmware_from_file(
_device_group, scpu_path, ncpu_path
)
```
**意涵**
- 我們既有用的是 **RAM-based load**(每次 connect 都重新 load 到 RAM、不寫 flash
- warrenchen 走兩條路:
- `kp.core.load_firmware_from_file`RAM-based、`firmware_legacy_plus121_load` endpoint 走這條)
- `lib.kp_update_kdp_firmware_from_files`flash-based、permanent、`update_kl720_firmware.py` 走這條)
- **PRD AC-FW-3.1KDP1 → KDP2 升版)的兩種實作策略**
- **策略 RAM-based**(既有 visionA-local 做法):每次 connect 重新 load、不寫 flash、永久效果需 USB 不拔
- **策略 Flash-based**warrenchen `update_kl720_firmware.py` 做法):寫進 flash 永久生效、device reboot 後 product_id 從 0x0200 → 0x0720
- A 階段選哪個策略需要 PM/Architect 在 PRD 中明示——**這是 PRD 缺失**、應該補
---
## 對 PRD AC-FW-3.5 的影響
`feature-firmware-management.md` AC-FW-3.5(推測為 KL630/KL730 升降版)的弱驗證結論:
| 項目 | 弱驗證結論 | 對 AC-FW-3.5 影響 |
|------|----------|------------------|
| SDK enum 存在 | ✅ 3.1.2 確認有2.0.0 待驗 | macOS/Linux 必先升 wheel |
| `update_kdp_firmware_from_files` API 存在 | ✅ 3.1.2 確認 | API 層可用 |
| 對 KL630/KL730 適用 | ⚠️ 無 reference 實作、warrenchen 沒做 | **參考實作為零、設計工時加倍** |
| .tar firmware 處理 | ✅ 走策略 Ybuild time 解壓)即可 | TDD §41 確定方案 |
| 實機驗證 | ❌ 必需 | M9-10 啟動前不能跳過 |
**建議**
- AC-FW-3.5 **不適合放 A 階段 MVP**——理由:
1. 無 warrenchen reference 實作design risk 高)
2. wheel 三平台不一致、A 階段要做 KL630/KL730 升降版必先處理 wheel 升級(額外 1-1.5 人天 + regression 風險)
3. 沒實機根本沒法 verify
- AC-FW-3.5 **延後到 B 階段 M9-10**
- 此時 M9-9KL630/KL730 connect + inference已實機驗過
- wheel 升級決策已根據 M9-6 強驗證結果決定
- 真正能寫 + 測 + 跑
---
## 對 TDD §X.X 的影響
需要立即修改的章節M9-6 弱驗證後就能改、不必等強驗證):
| 檔案 | 章節 | 修改內容 | 優先級 |
|------|------|---------|--------|
| `04-architecture/v2/firmware-management.md` | KneronPLUS wheel 版本 | 註記三平台不一致macOS/Linux 2.0.0、Windows 3.1.2+ A 階段是否升級的決策建議 | 高 |
| `04-architecture/v2/firmware-management.md` | `_resolve_firmware_paths` 設計 | **明示策略 Ybuild time 解壓)為唯一方案**、刪除策略 Z 描述 | 高 |
| `04-architecture/v2/firmware-management.md` | KL520 / KL720 升版策略 | 明示「RAM-based vs Flash-based」兩種方案差異、選定其一 | 高 |
| `04-architecture/v2/firmware-management.md` | KL630/KL730 升降版 | 標 "B 階段才實作、A 階段不開";附 warrenchen 沒做的事實 | 高 |
| `04-architecture/v2/firmware-management.md` | API call list | 補 `kp_connect_devices` + magic_pass 機制(從 warrenchen 確認的 pattern | 中 |
| `04-architecture/research-kl520-fw-management/41-tar-firmware-handling.md` | §4.4 決策樹 | 標策略 Z 已排除、走策略 Y | 高 |
| `04-architecture/research-kl520-fw-management/40-b-phase-kl630-kl730-extension.md` | §3.2 表格 | 填入「弱驗證結果」columnA 類 4 項) | 高 |
| `04-architecture/research-kl520-fw-management/40-b-phase-kl630-kl730-extension.md` | R-FW-8 | 升級為「中度風險」KneronPLUS 3.1.2 enum 確認後、剩 2.0.0 升級 + KL630/KL730 適用性風險) | 中 |
| `04-architecture/research-kl520-fw-management/50-m9-6-sdk-validation.md` | §8.1 / §8.2 / §8.3 | 填弱驗證結果(連結本檔) | 高 |
| `02-prd/features/feature-firmware-management.md` | AC-FW-3.5 | 標 "B 階段才實作、A 階段不開"、附 M9-6 弱驗證理由 | 高 |
---
## 強驗證仍需執行的項目
剩下的、必須等硬體 / Bash 才能驗:
| # | 項目 | 何時做 | 預估工時 | 是否阻塞 A 階段 |
|---|------|--------|---------|---------------|
| A-22.0.0 part | macOS + Linux 跑 `python3 -c "import kp; print(kp.ProductId.KP_DEVICE_KL630)"` | M9-6 強驗證階段(無需實機 dongle、只需 venv | 30 分鐘 | **是**——影響 wheel 升級決策 |
| A-5 | KL630/KL730 dongle + `lib.kp_update_kdp_firmware_from_files` flash 測試 | M9-10 啟動前 | 0.5 天 | 否A 階段不做 KL630/KL730 升降版) |
| A-6 | wheel 2.0.0 → 3.1.2 升級後 KL520+KL720 三平台 E2E | M9-13 | 1 天 | 否(如果 A 階段不升 wheel |
| B-1 | KL630/KL730 USB scan product_id | M9-9 啟動前 | 30 分鐘 | 否 |
| B-2 | KL630/KL730 是否每次 connect 重 load firmware | M9-9 | 1 小時 | 否 |
| B-3 | KL630/KL730 firmware 字串可能值 | M9-9 | 30 分鐘 | 否 |
| C-1 | `.tar` 內容(用 `tar -tvf`、無需實機) | M9-8 啟動前 | 5 分鐘 | 否(策略 Y 已確定) |
**A 階段啟動前必跑(阻塞)**:只有 A-22.0.0 wheel enum 驗證一項、30 分鐘可解。
---
## 給 Orchestrator 的建議
### 1. 弱驗證結論是否足以開始 A 階段開發?
**結論****可以**——但要先:
- 派 backend agent 在 macOS/Linux 跑 30 分鐘的 A-2 強驗證(即 `python3 -c "import kp; print(kp.ProductId.KP_DEVICE_KL630)"`
- 結果有兩個分支:
- **2.0.0 有 KL630/KL730 enum** → 不阻塞 A 階段、可以照原計畫做 KL520+KL720 PRD 範圍
- **2.0.0 沒有 KL630/KL730 enum** → 仍可不阻塞 A 階段A 階段不做 KL630/KL730但 PRD AC-FW-3.5 必須明示「需先升 wheel」
- 派 backend agent 跑 C-1`tar -tvf` inspect5 分鐘可解
### 2. 強驗證執行時機建議
- **立刻可做**無實機A-22.0.0 part+ C-1 → 30 分鐘 + 5 分鐘
- **M9-9 啟動前**B-1 + B-2 + B-3需 KL630/KL730 實機)
- **M9-10 啟動前**A-5需 KL630/KL730 實機跑 flash 測試)
- **M9-13**A-6三平台 wheel 升級 regression
### 3. 哪些 PRD/TDD 內容需要立即修改、哪些可等強驗證
**立即修改(不必等強驗證)**
- TDD `04-architecture/v2/firmware-management.md`
- `_resolve_firmware_paths` 走策略 Y、刪策略 Z
- 註記 wheel 三平台不一致 + A 階段升 wheel 與否決策
- KL630/KL730 升降版章節標「B 階段才實作」
- PRD `02-prd/features/feature-firmware-management.md`
- AC-FW-3.5 明示「B 階段才實作、A 階段不開」+ 理由
- 研究檔 `40-b-phase-kl630-kl730-extension.md` + `41-tar-firmware-handling.md`
- §3.2 / §5.2 / §4.4 填弱驗證結果
- 研究檔 `50-m9-6-sdk-validation.md`
- §8.1 連結本檔
**等強驗證才修改**
- wheel 升級最終決策(等 A-2 + A-6 強驗證)
- KL630/KL730 connect 流程設計細節(等 B-1 + B-2 + B-3
- KL630/KL730 升降版 API 選擇(等 A-5
### 4. 派工建議
- **A-2 強驗證**:派 backend agent、目標檔 `.autoflow/04-architecture/research-kl520-fw-management/55-m9-6-weak-validation-result.md` 補「A-2 強驗證結果」段落
- **C-1 強驗證**:同 backend agent 順手做、5 分鐘
- **TDD/PRD 修改**:派 architect agent做 TDD 修改、Orchestrator 自行修 PRD AC-FW-3.5 標註
---
## 與其他研究檔的關係
| 連結 | 引用內容 |
|------|---------|
| `50-m9-6-sdk-validation.md` §2 | 本檔 §「Unknown 對照表」對應該檔 10 個 unknown |
| `50-m9-6-sdk-validation.md` §8 | 本檔結果應回填到該檔 §8.1 / §8.2 / §8.3(弱驗證部分) |
| `40-b-phase-kl630-kl730-extension.md` §3.2 | 本檔「重點發現 1」確認 KneronPLUS 3.1.2 enum 列表 |
| `40-b-phase-kl630-kl730-extension.md` R-FW-8 | 本檔降低該風險等級(部分 unknown 已解) |
| `41-tar-firmware-handling.md` §4.4 | 本檔「發現 4」+「Unknown 對照表 A-3/A-4」確認策略 Y 唯一可行 |
| `41-tar-firmware-handling.md` §5.1 表格 | 本檔「Unknown 對照表」對應該檔 #1-#10 |
| `feature-firmware-management.md` AC-FW-3.5 | 本檔建議延後到 B 階段 |
| `feature-firmware-management.md` 全表 | 本檔「發現 7」指出 PRD 缺「RAM-based vs Flash-based」明示 |
---
## 執行限制與不確定性聲明
**本弱驗證的限制**
1. **無法直接讀 wheel 內 Python source**——所有結論透過 warrenchen 程式碼間接證據推得
2. **無法跑 Python REPL**——`KP_DEVICE_*` enum 值(整數)未知;只知道**名稱**存在於 SDK
3. **無 Bash**——無法 `unzip` wheel、`tar -tvf` firmware
4. **無實機**——B 類全部 + A-5 + A-6 都需要實機
**可能的錯誤來源**
1. warrenchen 程式碼可能用了**過時 / 不推薦**的 SDK API`KP_DEVICE_KL720_LEGACY` 在更新 SDK 版本可能被 deprecate本驗證假設「warrenchen 用的 API 就是 SDK 該版本支援的 API」
2. 我們既有 visionA-local 用的是 KneronPLUS 2.0.0、warrenchen 是 3.1.2——**所有結論都是基於 3.1.2 的觀察**、2.0.0 行為可能不同
3. ctypes-level `lib.kp_*` 跟 Python `kp.core.*` wrapper 簽名可能不同(極少數情況);本驗證假設兩者語意相同
**修正路徑**上述任何懷疑、M9-6 強驗證階段(有實機 + Bash + REPL都能 5 分鐘內 confirm 或 refute。本弱驗證的價值不在「100% 確定」、在「**剃掉一半 unknown、把 A 階段不阻塞的部分先過、把真的需要硬體的部分留到 M9-9 / M9-10 / M9-13**」。