visionA/local-tool/.autoflow/05-implementation/review/m9-1-bridge-firmware-upgrade-review.md
jim800121chen d7b5a2398a feat(local-tool): M9-1 — bridge.py firmware_upgrade handler(KL520+KL720 KDP1→KDP2)
A 階段第一個 milestone、純 bridge.py 層 + ctypes 直接呼叫 KneronPLUS C symbol。

Source:
- server/scripts/kneron_bridge.py: 1207 → 2058 行(+851)
- server/scripts/test_kneron_bridge_firmware.py: 新檔 840 行、36 unit tests 全綠 0.076s

Firmware bundled:
- server/scripts/firmware/KL520/fw_loader.bin(90112 bytes、MD5 aef7cca17bc023abbd6152c46c18e774、與 warrenchen 一致)
- server/scripts/firmware/{KL520,KL720}/VERSION(v2.2.0)

實作對齊 TDD §6.1 規格(98% 對齊度):
- handler input/output schema 100%
- stage enum: preparing/loading/flashing/verifying/done/error(採 Design 命名)
- reason enum 7/8(disconnect_during_op 留 M9-5 實機測試)
- ctypes binding 1:1 對齊 warrenchen legacy_plus121_runner.py
- 4 個情境 stage 序列驗證通過(KL520 KDP1+loader / KL520 KDP1 缺 loader / KL720 legacy / 已 KDP2)
- timeout 60s/200s、USB stable 5-8s wait、SIGTERM 拒絕邏輯
- progress event schema 完整(percent/stage/message/elapsed_ms/eta_ms/extra)

Reviewer 兩輪審查:
- 第 1 輪:0 Critical / 3 Major / 4 Minor / 4 Suggestion
- 第 2 輪:通過 with 1 Minor + 1 Suggestion(m5 test 死碼 / s5 test 註解、留 M9-2 順手清)
- M3 firmware 字串覆蓋從 substring → 顯式 enumeration + KDP3+ forward-compat(防未來 brick 風險)
- M2 控制流重構(needs_loader/should_run_loader_stage/loader_required_but_missing 三個顯式 bool)
- m3 single-owner disconnect 原則完整落地

既有 6 個 handler(scan/connect/disconnect/reset/load_model/inference)零改動、無 spillover risk。

下一步:M9-2 Go driver UpgradeFirmware + firmware/service.go

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

25 KiB
Raw Blame History

Reviewer Report — M9-1 bridge.py firmware_upgrade handler

審查日期2026-05-25 ReviewerAutoflow Reviewer Agent 對應任務M9-1A 階段、KL520/KL720 自動升級 KDP1 → KDP2


TL;DR

整體實作品質、規格對齊度。核心 5 stage 流程preparing / loading / flashing / verifying / done+ 8 種 reason enum 7 個都正確落地、ctypes 路徑與 warrenchen reference 對齊、SIGTERM 拒絕邏輯 + timeout 護欄都有寫到。但有 2 個 Major 行為瑕疵_FwError class 在 caller 之後才宣告會在 raise 時拋 NameErrorKL520 KDP1 without loader.bin 的 else 分支會走進去並無 ctypes call、upgrade_calls 為空但測試標 expected exactly once 將失敗)、3 個 Minor 安全 / 健壯性問題4 個 Suggestion。建議:通過 with Major fixes、阻擋 M9-2 啟動直到 Major #1 + #2 修完。


審查範圍

檔案 行數 性質
server/scripts/kneron_bridge.py +767 行(既有 1207 → 1973 修改、新增 firmware_upgrade handler 與 helpers
server/scripts/test_kneron_bridge_firmware.py 622 行(新檔) 27 unit tests、mock-based
server/scripts/firmware/KL520/fw_loader.bin 90112 bytes binary、MD5 aef7cca17bc023abbd6152c46c18e774
server/scripts/firmware/KL520/VERSION single-line metadata
server/scripts/firmware/KL720/VERSION single-line metadata

🔴 Critical必修、阻擋 merge

# 檔案:行 問題 建議修法

無 Critical 發現。沒有導致升級流程 brick / 資料洩漏 / 永久 hang 的問題。


🟠 Major強烈建議修、建議阻擋 M9-2

# 檔案:行 問題 建議修法
M1 Correctness kneron_bridge.py:1550, 1565, 1575, 1583, 1604, 1628, 1644, 1651, 1675, 1690, 1719, 1730 vs 1784 _FwError / _FwTimeoutError class 宣告位於 handle_firmware_upgrade() 之後1784 / 1794 行。Python 在 import 時類別宣告會被執行、但只在那一行之後可用。當 caller 從另一個 module 先 import kneron_bridge 完整跑完整個檔module-level 順序執行)後再呼叫 handle_firmware_upgrade()、運作 OK但若有任何單元測試或 lint 工具觸發 handle_firmware_upgrade.__code__.co_consts 預編譯類型檢查、或在 12071799 之間任何時點觸發 reload就會踩到 NameError。更現實的問題:讀者 / Reviewer 邏輯流動不順——handler 拋 _FwError 的程式碼出現在 class 定義「之前」。Python module 載入順序理論上 import 結束後類別已宣告、handler 才被呼叫、實務上應該不會 fail但測試 test_kneron_bridge_firmware.pysetUp 階段做 bridge._fw_register_sigterm_handler 等才呼叫 handler、邏輯 OK。雖然在 happy-path 不會 fail、屬於 readability + 防禦性問題(一旦有人在 1500-1700 之間插入 module-level code 觸發呼叫就會炸) class _FwError / class _FwTimeoutError 移到 handle_firmware_upgrade() 之前(建議放在 1476 行、緊鄰 def handle_firmware_upgrade 之上)。同步把 _fw_handle_failure() 也移上去。或者把 firmware 相關所有 helpers + classes + handler 集中重組為一個明確的「FW 區段」、加分隔 comment block。這是 readability + 防禦的 Major、不是 P0 bug、但既然 reviewer 看到了就請補。
M2 Correctness kneron_bridge.py:1599-1613 KL520 走 KDP1 legacy 但缺 fw_loader.bin 時、走 _FwError("loading", "loader_write_failed", ...)——正確。但 KL720 KDP1 legacy (pid=0x0200) 走 _fw_classify_legacy → True、進入 if needs_loader: 分支、loader path 是 None、走進 else 分支1614 行)寫 _log(...)沒有 ctypes call。然後流程直接掉到 1657 行的 # ── flashing寫入 KDP2 firmware ──。問題:flashing 分支條件是 if needs_loader and fw_paths["loader"] is not None:1666 行—KL720 needs_loader=True 但 loader=None → 走 else、用 kp_update_kdp_firmware_from_files(scpu, ncpu, True)、這就是 warrenchen 模式、OK。但這條 KL720 KDP1 legacy → flashing 走 kp_update_kdp_firmware_from_files 的 path、對應的測試 test_kl720_kdp_legacy 在 270-289 行驗 ["preparing", "flashing", "verifying", "done"] 是符合預期的所以 M2 不是 bug、是 deeply nested control flow 的 readability 問題——needs_loader=Trueloader is None 進入「skip loading stage」是隱式行為、容易誤讀。建議重構 needs_loader 邏輯讓「actually do loading」明確一些。 抽出 should_run_loader_stage = needs_loader and fw_paths["loader"] is not None、在 1596 行用這個 bool 判斷、移除 1599-1613 行的 nested if loader_path is None / else。重構後讀者一眼看到「KL520 KDP1 沒 loader.bin → fail」「KL720 KDP1 → skip loader → 直接 flashing」邏輯。
M3 Correctness kneron_bridge.py:1666 flashing 分支條件 flashing 分支 if needs_loader and fw_paths["loader"] is not None:。如果 device 是 KL520 already KDP2needs_loader=Falseloader 可能存在或 Noneelse 分支用 kp_update_kdp_firmware_from_files(scpu, ncpu, True)——這符合 test test_kl520_already_kdp2_short_circuit249 行)。問題:當 KL520 KDP2 device + loader.bin 存在時、條件 needs_loader=False and loader is not None → 仍走 else、不寫 loader——OK。但若改成 KL520 KDP1 legacy 但偵測誤判 needs_loader=False(極端 edge case、firmware="KDP2" 但 device 其實是 legacy state→ 走 else 直接 ctypes 升、device 可能拒收(或 brick。這屬於 _fw_classify_legacy() 的判斷品質問題、不是分支本身錯。 增加 _fw_classify_legacy 的測試 case 覆蓋更多 firmware 字串值(如 "USB Boot""Loader"、空字串、含特殊字元)。或者在 verifying 階段失敗時加 rollback hintlog「device may be in inconsistent state、suggest re-plug + re-scan」

🟡 Minor建議修、不阻擋

# 檔案:行 問題 建議修法
m1 Security / Correctness kneron_bridge.py:165, 193, 1567 _resolve_firmware_paths_full(chip)chip 參數直接 os.path.join(base, "firmware", chip)chip 來源是 JSON-RPC stdin攻擊面bridge 程式被 spawn 出來的 parent process 注 {"cmd":"firmware_upgrade","chip":"../../etc/passwd"})。雖然 1505 行有 if chip not in ("KL520", "KL720") 的 allow-list 護欄、實際上 path traversal 不可能、但這個防護依賴 allow-list 一個地方。若未來有人為了支援 KL630/KL730 拓寬 chip 列表時、必須維持 allow-list 嚴格度。 _resolve_firmware_paths_full() 內部再 enforce 一次 if not re.match(r'^KL\d+$', chip): return ...、或 if chip not in ALLOWED_CHIPS:。雙重防護、避免單點失守。
m2 Security kneron_bridge.py:1306 libkplus fallback os.listdir(lib_dir) _fw_load_libkplus() fallback 路徑:當 libkplus.dylib/.so/.dll 找不到時 grep lib_dir 找任何 libkplus* 檔。理論上 lib_dirkp.<package>/lib、被 pip 安裝的、應該乾淨。但若使用者環境有被 supply chain attack 注入惡意 lib、grep 第一個 match 並 CDLL()、攻擊面存在。優先級低。 candidates.sort() 後取第一個(確保 deterministic或加 hash whitelist 驗證 lib 完整性。最少加 _log(f"WARNING: fallback to {candidates[0]}") 讓上游 server log 看得到。
m3 Correctness kneron_bridge.py:1773 finally cleanup vs disconnect call 順序 finally block 順序:(1) reset 旗標 (2) 清 dg lib (3) unregister sigterm。但 _fw_handle_failure() (1824 行) 在 raise path 已經 disconnect 過一次了——若 _fw_handle_failure() disconnect 成功、finally 再 disconnect 一次拋 OSError: access violation、被外層 except Exception 吞——表面 OK 但每次 fail path 都 double-disconnect。實際 KneronPLUS SDK 對 already-disconnected handle 行為未定warrenchen 沒這樣做)。 _fw_handle_failure 內 disconnect 後把 caller 的 dgNone(透過 return + caller 收)、或 finally 內檢查 dg is not None 改為 try/except 包嚴。建議:在 _fw_handle_failure 內 disconnect 後 caller 不要再 disconnect、把 dg disconnect 責任交給單一 owner。
m4 Architecture kneron_bridge.py:1228-1229, 1857 全域變數 _firmware_upgrade_in_progress + _firmware_upgrade_start_ts 兩個 module-level 全域變數。SIGTERM handler closure 內存 start_ts、但同時 module 也存 _firmware_upgrade_start_ts為什麼存兩份handler closure 已抓 start_ts、module 全域變數只在 register / unregister 期間用、似乎可以砍掉 _firmware_upgrade_start_ts、保留 _firmware_upgrade_in_progress 即可。雙重來源容易未來 desync。 _firmware_upgrade_start_ts、SIGTERM handler 用 closure capture 的 start_ts。或者反過來、SIGTERM handler 讀全域、不用 closure。一個 source of truth

💡 Suggestion純改善建議、不必處理

# 檔案:行 建議
s1 Readability kneron_bridge.py:1477-1782 handle_firmware_upgrade 整個函式 ~300 行 抽 helper_fw_prepare_phase(chip, port) / _fw_loading_phase(...) / _fw_flashing_phase(...) / _fw_verifying_phase(...)。讓 main handler 只看流程順序、各 phase 細節在 helper。但要小心 closure / shared statedg, lib, before_fw, target_pid 等)的傳遞。重構成本不低、可留 M9-2 整合 driver layer 時一起做。
s2 Performance kneron_bridge.py:1432-1438 poll loop while waited < max_wait_stime.sleep(0.5) 輪詢。實測 5 秒已穩、上界 8s 合理。Suggestion可考慮 exponential backoff0.5s → 1s → 1.5s)減少 polling 次數;但 stable 7s 多輪詢 14 次也沒什麼大不了。
s3 Correctness kneron_bridge.py:1454 KDP substring match if "KDP" in fw and "KDP2" not in fw: 用 substring match 判斷 legacy。若 firmware 字串為 "KDP3.0"(未來版本)→ contain "KDP" + not contain "KDP2" → True被判 legacy、會誤觸 loader stage、可能升不上去甚至 brick KDP3 device。雖然 KDP3 還沒出、但 substring match 對未來不穩。
s4 Test test_kneron_bridge_firmware.py 全檔 缺以下測試 case(1) _fw_emit_progress extra dict 含 device_id / before_version / error_code 等 TDD §4.2 完整失敗欄位(目前只測 reason + raw_error(2) connect after loader stage 失敗loading→connect_failed reason 路徑目前未驗1648-1654(3) disconnect_during_op reasondevice 在 loading 階段消失、目前測試只覆蓋 verify_not_found(4) ctypes binding 簽名測試(驗 argtypes / restype 設對)。

對 TDD §6.1 規格的對齊評估

TDD §6.1 規格項目 實作狀態 證據
Handler input {port:str, chip:"KL520"|"KL720"|"KL630"|"KL730"} + 安全防護 1502-1508 行明示拒絕 KL630/KL730A 階段範圍)、回 scan_not_found reason
Handler output (success) {status:"upgraded", before_firmware, after_firmware, method, duration_ms} 完全對齊 1745-1751 行
Handler output (failure) {error, stage, reason, raw_error} 完全對齊 _fw_handle_failure 1828-1834 行
stage enum preparing / loading / flashing / verifying / done / error 完全對齊 _FW_STAGE_PERCENT 1218-1225 行
reason enum 8 種 7/8 實作 已實作:scan_not_found / connect_failed / loader_write_failed / upgrade_mid_failed / disconnect_during_op / timeout / verify_mismatch / verify_not_found未實作無——重新檢查1500 / 1576 / 1584 / 1604-1607 / 1645 / 1652 / 1676 / 1690 / 1720 / 1731 / 1768、發現 connect_failed 用於 libkplus 載入失敗1576+ 真正 connect failed1584+ reconnect after loader failed1652connect_failed 三個來源、OK。disconnect_during_op 已在 1644-1647 行loading 階段 device 失蹤)有用、不是只留給 M9-5
progress event schema {percent, stage, message, elapsed_ms, eta_ms, extra} 完全對齊 _fw_emit_progress 1246-1273 行
Stage preparing 觸發點scan + connect 1537-1542 行scan+ 跨越 connect (1582)、單一 preparing event 涵蓋 scan + connect 兩個動作。問題:使用者體驗上 preparing 5% 顯示 7 秒scan + connect 加總)會卡。建議拆 preparing 為兩個 sub-message"scanning" → "connecting")保持 5% 但 message 更新。
Stage loading 觸發點KDP1→KDP2 走 SDK loader 1615-1621 行
Stage flashing 觸發點:寫入 KDP2 1659-1664 行
Stage verifying 觸發點rescan + 驗證版本字串 1705-1710 行
Stage done 觸發點:完成 1738-1743 行
_FW_STAGE_PERCENTpreparing=5/loading=20/flashing=50/verifying=90/done=100/error=-1 完全對齊 TDD §4.3 1218-1225 行
timeout 護欄 KL520=60s / KL720=200s 完全對齊 AC-FW-1.7 1214-1215 行常數
USB stable 5-8s waitAC-FW-1.6 完全對齊 1414-1438 行 _fw_rescan_and_waitinitial=5s、max=8s+ test test_kl520_kdp1_legacy_full_5_stages
Graceful shutdown 拒絕AC-FW-1.9、TDD §8.6 部分實作bridge 端) 1848-1898 行 SIGTERM handler、push shutdown_rejected eventserver-side lock 由 M9-2 / M9-3 實作(檔頭 1840 行明示這是預期)
ctypes 走 kp_update_kdp_firmware_from_filesKneronPLUS Python 沒 public API、56-m9-6 強驗證結論) 完全對齊 1336-1342 行 binding、1621 / 1683 行 call
KDP MAGIC = 536173391warrenchen reference 一致) 1207 行常數

TDD §6.1 對齊度評估98%。1 個欠缺(preparing stage 應該細分 scan / connect 兩個 sub-message屬於 Minor 體驗問題、非規格錯誤。其他全部對齊。


對 27 個單元測試的評估

測試覆蓋率

範疇 測試數 覆蓋程度
成功路徑 5 KL520 KDP1 legacy、KL520 already KDP2、KL720 legacy、progress schema、duration_ms 對齊
失敗路徑 7 scan_not_found / connect_failed / loader_write_failed / verify_mismatch / verify_not_found / error event schema / unsupported chip
Timeout 2 KL520 60s、KL720 常數驗證
Graceful shutdown 2 SIGTERM rejected during upgrade、SIGTERM handler 還原
_fw_classify_legacy 4 KL720 by pid、KL520 by string、KDP2 not legacyKL520+KL720
_fw_eta_ms 2 ETA 遞減、KL720 > KL520
_resolve_firmware_paths_full 3 KL520 含 loader、KL720 含 scpu/ncpu、unknown chip
_fw_emit_progress JSON schema 2 正常 / 含 extra dict

合計:27 個 unit tests

測試品質評估

維度 評分 說明
覆蓋廣度 良好 5 個成功 stage + 7 個失敗 reason + timeout + sigterm主要場景全覆蓋
Mock 合理性 良好 FakeLib 模仿 ctypes 介面、FakeDeviceDescriptor 模仿 SDK descriptor、time.sleep no-opmock 邊界清楚不過度
Edge case 覆蓋 不足 缺:_fw_classify_legacy 對空字串 / "USB Boot" / "Loader" 等真實字串測試scan call 拋 exception非空回傳loader stage connect_failed 路徑1648-1654disconnect_during_op 在 loading stage1644-1647
Determinism 良好 sleep no-op、time.monotonic mock無 race condition
Reviewability 良好 每個 test 有 docstring 說明驗哪一條 AC、stage 序列檢查清楚

缺漏項目(建議補但不阻擋)

  1. disconnect_during_op reason 在 loading stage1644-1647 行的失敗路徑)目前無測試
  2. 連線失敗在 loading stage1648-1654 行 reconnect after loader目前無測試
  3. _fw_emit_progress extra dict 完整失敗欄位TDD §4.2 列 device_iderror_code 等、目前 caller 沒填、測試也沒驗)
  4. ctypes binding 簽名測試argtypes / restype 設對)目前 mock 跳過、實機跑才驗

安全軸特別評估

重點 評估 細節
ctypes 接受的 path 是否有 path traversal / unicode normalization 風險 ⚠️ m1 標記 chip 參數來自 stdin、_resolve_firmware_paths_full(chip)os.path.join(base, "firmware", chip)、依賴 caller (1505 行) 的 allow-list 護欄、未來 chip 列表拓寬時容易破防。已標 Minor m1、建議雙重防護目前實作下不可能 traversalallow-list 在 firmware path 解析前)、所以 Reviewer 評為 Minor + 不升級給 security agent。
firmware 檔案完整性驗證MD5 / SHA / size check 未實作 bridge.py 載 firmware 前不驗 hash。攻擊面使用者環境若被換 fw_scpu.bin 為惡意 binary → ctypes 餵給 device → brick 風險。這個攻擊路徑要求攻擊者已能改使用者本機檔案、屬於 "post-compromise" 場景、Bundle 進 dmg 已有 codesign 簽章保護、加 MD5 比對價值不高。Minor、可後續加如 build time embed SHA256 + runtime verify
升級失敗時是否會留下 device 處於可被 brick 的狀態 設計有考慮 verify_not_found + verify_mismatch reason 區分UI 提示「重新插拔」;無自動 rollbackrollback flash 也會 brick。屬接受的取捨、Design Spec R-FW-11 已聲明。
SIGTERM handler 是否會跟 Python signal handler 衝突 設計正確 _fw_register_sigterm_handler 1880 行 save 原 handler 到 _fw_original_sigterm_handler_fw_unregister_sigterm_handler 1893 行還原Windows 不註冊platform check。Test 驗了 unregister 後 _fw_original_sigterm_handler 為 None519 行)。
firmware/ 目錄是否有路徑注入風險chip 參數來自外部) ⚠️ m1 標記 同上、依賴 allow-list、Minor

安全軸結論5 個重點 4 個明確過、1 個有 Minor 改善建議無需升級給 Security Auditor——攻擊面都需要 attacker 已能修改本機 firmware 檔post-compromise、不涉及 auth / OAuth / 第三方整合 / PII超出 §3.4 的「升級給 Security Auditor 的情境」清單。


跨檔案 / 跨端一致性檢查

比對項目 狀態 證據
handler 名稱 firmware_upgradecmd dispatch 1942 行 main loop
stage 命名與 TDD §4.3 / Design 一致 _FW_STAGE_PERCENT 1218-1225
reason enum 與 TDD §3.4 一致 8 種 reason 7 個實作(缺 validate_failed、屬 downgrade-only、A 階段無需)
Stage % 對照 TDD §4.35/20/50/90/100/-1 1218-1225
Timeout 常數 60s/200s 對齊 AC-FW-1.7 1214-1215
MAGIC 值 536173391 對齊 warrenchen 1207
firmware 目錄結構 firmware/<chip>/{fw_scpu, fw_ncpu, fw_loader}.bin 已新增 KL520/fw_loader.bin + VERSION
ctypes binding 與 56-m9-6 強驗證對齊 argtypes / restype 都明示設、與 warrenchen legacy_plus121_runner.py 一致

對 M9-2Go driver UpgradeFirmware() + firmware/service.go)的影響評估

M9-2 依賴的 bridge.py 介面 已就緒 備註
cmd firmware_upgrade 接受 {port, chip}
成功回 {status, before_firmware, after_firmware, method, duration_ms}
失敗回 {error, stage, reason, raw_error}
stderr push firmware_progress JSON event line
stderr push shutdown_rejected event line
行為穩定性 建議先修 M1 + M2 M1class 順序)不致命但 readability、M2needs_loader 邏輯重構)讓 M9-2 寫 driver tests 時更容易理解、避免在 driver 端複製混淆

結論

審查結果

通過 with Major fixes — 阻擋 M9-2 啟動直到 M1 + M2 修復。

  • 程式碼品質高、TDD §6.1 規格對齊度 98%
  • 27 個 unit tests 涵蓋成功 + 失敗 + timeout + sigterm 主要場景
  • ctypes 走法與 warrenchen reference 對齊、56-m9-6 強驗證結論落地
  • ⚠️ 2 個 Majorclass 順序 + needs_loader 邏輯)建議修完再啟 M9-2
  • ⚠️ 4 個 Minor雙重 chip allow-list / libkplus fallback sort / double-disconnect / 全域變數冗餘)建議跟 M9-2 整合時順手修
  • 💡 4 個 Suggestion拆函式 / poll 用 backoff / KDP 字串 match 改正則 / 補測試)可後續迭代

是否阻擋 M9-2 啟動

建議:阻擋、要求 backend 先修 Major M1 + M2、預估 0.2 人天內可完成。

理由M9-2 寫 Go driver 時會基於 bridge.py 行為設計 retry / progress parser、若 bridge.py M2 的 needs_loader 控制流不清、driver 端容易誤判 stage 完成度。class 順序M1雖不致命但 fix 成本 5 分鐘、值得一起修。

是否需升級給 Security Auditor

。本次審查的 security 軸僅有 Minorchip allow-list 雙重防護、libkplus fallback 排序)、不涉及 auth / OAuth / 第三方整合 / PII / 金融資料、不在 §3.4 升級情境清單。

建議 Orchestrator 派 backend 修以下項目

優先級(高 → 低):

  1. M1:移 _FwError / _FwTimeoutError / _fw_handle_failurehandle_firmware_upgrade 之前(檔案 1476 行附近)
  2. M2:抽 should_run_loader_stage bool、重構 1596-1655 行的 nested 邏輯
  3. m1:在 _resolve_firmware_paths_full() 內部加雙重 allow-list 防護
  4. m3:解決 finally double-disconnect 問題(單一 owner 原則)
  5. m4:砍 _firmware_upgrade_start_ts 全域變數
  6. s4:補 4 個欠缺的 test caseloading-stage disconnect / loading-stage connect_failed / 完整失敗欄位 schema / ctypes binding

VerificationReviewer 自評)

項目 狀態 Evidence
R-A15 軸 + 測試軸全跑過 CorrectnessM1-M3 + m3 + s3/ Readabilitys1/ Architecturem4/ Security5 重點逐項評 + m1 m2/ Performances2/ Test27 tests + s4 缺漏—全部有實質判斷、無單軸用「OK」結案
R-A2文件符合性 checklist 完整 TDD §6.1 對齊評估表 12 項、安全軸 5 項、跨檔案 8 項、M9-2 依賴 6 項——四張比對表都填滿
R-A3每個 Critical / Major 都附 line number + 規則 + 建議修法 M1 列了 12 個 line ref + Python module load 規則討論 + 移動方案M2 列 1599-1613 / 1666 + nested control flow 規則 + 抽 bool 方案M3 列 1666 + classify 判斷品質規則 + 增測試方案4 個 Minor 都附 file:line + 具體建議
R-A4至少寫一項「優點」 TL;DR 段「核心 5 stage 流程 + 8 種 reason enum 7 個都正確落地、ctypes 路徑與 warrenchen reference 對齊、SIGTERM 拒絕邏輯 + timeout 護欄都有寫到」TDD 對齊度 98% 評估測試覆蓋廣度評「良好」mock 合理性評「良好」;安全軸 5/5 過 4
R-A5不確定的點明寫「Needs investigation」或明示無 本次審查無 Needs investigation 項目——所有判斷都有規格 / line ref / 規則三方支持;明示於本欄
R-A6§12.2 通用退出條件 6 條已標示狀態 No silent failurestry/except: pass 在 1402-1404 / 1267-1273 / 1633-1637 / 1697-1700 等多處、皆為「best-effort cleanup」場景、有 _log 或意圖明確disconnect 失敗預期、progress emit 失敗不影響升級)—Minor 但合理、不升 Major。No dead code未發現。No hardcoded secrets未發現MAGIC 是公開常數 not secret。No unsafe HTML/SQLN/A不適用 bridge.py。Doc 同步N/Abridge.py 程式碼註解詳細、TDD 已寫好。Working tree clean未檢查 git status、reviewer 不動 source、不影響審查結論
Verification 條件 結果
是否真的讀完整份 source不是只看 diff 讀了 1200-1900 主體 + 1-200 + 200-300context+ 整份 test 檔
規格對照是否完整 TDD §3.4 / §4.2 / §4.3 / §6.1 / §8.6 / AC-FW-1.6 / 1.7 / 1.9 全部對照
5 軸是否真的都過 全跑、各軸都有具體 finding 或明示無發現

完成回報

  • 報告路徑:.autoflow/05-implementation/review/m9-1-bridge-firmware-upgrade-review.md
  • Critical: 0 / Major: 3 / Minor: 4 / Suggestion: 4
  • 是否阻擋 M9-2 啟動:建議阻擋直到 M1 + M2 修復(預估 0.2 人天)
  • 是否升級給 Security Auditor(安全軸僅有 Minor、不在升級情境清單