|
|
e27d8e3bd2
|
fix(local-agent): camera pixel format + rawvideo decoder(實測出畫面)
avfoundation 修好後實測發現兩層問題(camera 三層根因的後兩層):
- 改動1(args):darwin buildCaptureArgs 加 -pixel_format uyvy422(放 -i 前)。
攝影機只支援 uyvy422/yuyv422/nv12(非 yuv420p),不指定→協商失敗 I/O error。
- 改動2(ffmpeg):Makefile decoder 白名單加 rawvideo。攝影機吐 raw uyvy422
codec=rawvideo,轉 mjpeg 前要解,精簡 build 漏了→ no decoder found→EOF。
本機真攝影機端到端實測:/tmp/cam_ok.jpg = JPEG 640x480(rawvideo native→
mjpeg native 全鏈通、真的出畫面)。reviewer 通過(0C/0M)。只影響 camera
(video/image/batch 解既有壓縮檔、不碰 rawvideo/avfoundation)。只改 macOS
(Windows/Linux full build 內建 rawvideo;pixel_format 待實機 follow-up)。
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
2026-08-03 00:53:35 +08:00 |
|
|
|
a6c94e21c5
|
fix(local-agent): 重啟自動從 token.bin 讀 token,免每次重配對
app.go 只在 env VISIONA_SESSION_TOKEN 有值時才啟動 tunnel、env 空就等 UI Pair,
從沒觸發 token.bin 的載入 → 每次重啟都要重配對。(Manager.startLocked 本來就會
從 config.TokenStore.Load,只是沒被呼叫。)
修法:抽 shouldAutoStartTunnel — env 有 token 用 env(優先序不變);env 空則
tokenStore.Load(),有值就自動 Start(免重配對)、空/err/nil store 等 UI Pair 不擋啟動。
Unpair→Delete token.bin→重啟 Load 回空→不自動連(round-trip test 覆蓋)。
reviewer 通過(0C/0M/1m 雙Load技術債)。build/vet/test 全過 + 5 分支 + Unpair round-trip 測試。
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
2026-08-02 18:54:09 +08:00 |
|
|
|
f6d15b7b14
|
docs(arch): B 設備管理 + C 模型共享 + camera ADR-020 規劃文件
- feature-device-mgmt-tdd.md + api-device-mgmt.md(B 設備管理 TDD)
- feature-model-sharing-tdd.md + api-model-sharing.md + PRD feature + 設計規格(C 模型共享三方規劃)
- adr-020-ffmpeg-camera-indev.md(camera 三平台 indev)
- PRD.md / TDD.md 索引增補
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
2026-08-02 16:31:38 +08:00 |
|
|
|
6a797d5eb5
|
feat(frontend): 設備管理三態/註冊 + 模型共享庫/公開設定(B + C)
B 設備管理:device-store 補 registeredAt + register/unregister actions;
deriveTriState 三態(已連接/未連接/已連接未註冊);三態 badge(warning token
+ icon + 文字不只色);排序/filter chips;註冊 UI(明確區分取消註冊≠移除)。
C 模型共享:/models/library cursor 無限捲動 + 搜尋/filter/排序;visibility badge
三態;公開設定 Dialog(RadioGroup + shares 管理 + public 警告 + 二次確認);
profile 頁 owner/公開雙態;radio-group 新元件;owner 用 name 不洩 email。
共用檔 types/api.ts(B error codes)+ i18n en/zh(devices.* B / models.* C)。
零新 Design Token。reviewer B(0C/0M) + C(0C/0M、設計12/12 API8/8) 通過。
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
2026-08-02 16:30:22 +08:00 |
|
|
|
47a1d4d0ef
|
feat(backend): 設備註冊 + 模型共享 backend(B 設備管理 + C 模型共享)
B 設備管理(feature-device-mgmt-tdd):
- POST /api/devices/:id/register + /unregister(owner 檢查 + representative 擋
+ 已註冊擋 + SetRegistered 單欄翻轉,不碰 unpair 軟刪)
- error codes ALREADY_REGISTERED / REPRESENTATIVE_DEVICE(409)
- 不需 migration(registered_at 欄/index/讀寫已在 0005)
C 模型共享(feature-model-sharing-tdd,security 深審 APPROVE):
- migration 0006:models.visibility enum DEFAULT 'private'(零行為改變)+ model_shares 表
- canAccessModel single source(owner ∪ share ∪ public ∪ tenant):profile + download 共用
- GET /library(cursor keyset)/ GET /:id/profile(404 防列舉、GetWithOwner join name 不洩 email)
/ PATCH /:id/visibility(owner-only)/ shares CRUD / download 放寬
- tenant 因 OIDC 無 org claim 留 stub(恆空、安全預設;補 org claim 需重送 security 深審)
reviewer 通過(B 三條紅線 / C security APPROVE 無 C/M)。130 dbtest 全綠、gosec 新檔 0。
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
2026-08-02 16:29:50 +08:00 |
|
|
|
17134e8eae
|
feat(local-agent): camera 三平台 input device(ADR-020 WP-1/2)
camera 即時推論開不了根因:vendor decoder-only ffmpeg --disable-everything
沒 enable 任何 input device → macOS avfoundation 認不得。
- WP-1 macOS:ffmpeg rebuild 加 --enable-avfoundation + --enable-indev=avfoundation
(--disable-autodetect 會靜默 disable、兩行要一起帶)。-list_devices 列出相機、
+22KB、LGPL-safe。sha 已核對。
- WP-2:buildCaptureArgs 補 Linux v4l2 分支(原誤落 avfoundation default 必壞)+
ListFFmpegDevices Linux glob /dev/video*。四路明確 case + 回歸鎖。
reviewer WP-1(0C/0M/0m) + WP-2(0C/0M/2m) 通過。Windows dshow / Linux v4l2 實機驗待機器。
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
2026-08-02 16:28:51 +08:00 |
|
|
|
e4d27594d6
|
fix(local-agent): 修 camera 即時推論開不了(macOS 攝影機權限 + 假成功)
三層疊加根因:
1. 主根因:.app 缺 NSCameraUsageDescription → macOS TCC 靜默拒絕、不彈授權
視窗、綠燈不亮、ffmpeg avfoundation 抓不到 camera。
2. ffmpeg cmd.Start() 只要 fork 成功就回 nil → HTTP 200 假成功(攝影機沒真開)。
3. cmd.Stderr=nil 吞掉 ffmpeg 錯誤 + pipeline 靜默重試 → 極難查。
修法:
- Info.plist + Info.dev.plist 加 NSCameraUsageDescription(wails build template,
ad-hoc 簽名下只需 usage description,刻意不加 hardened runtime/entitlement
避免 TCC 直接拒絕)
- ffmpeg WaitForFirstFrame:收到首張完整 JPEG frame 才回成功;早退/逾時回明確
錯誤 → camera/start 真的回非 200、前端看到真實失敗。timeout 25s(涵蓋首次
TCC 授權彈窗的使用者反應時間;已授權情境仍秒開)
- stderr 導到有界 ringBuffer + log;pipeline camera 模式連續失敗 50 次結束
reviewer 通過(0C/0M/2m)。只動 camera 鏈路(影片/圖片/批次/tunnel 上傳不受影響)。
build/vet/test/gosec 過、4 新 camera 測試。
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
2026-08-02 03:48:30 +08:00 |
|
|
|
44b877318d
|
fix(frontend): 「開始推論」按鈕只在 camera 分頁顯示
「開始/停止推論」按鈕是 Camera 即時攝影機專用(打 /api/camera/start),
但原本渲染在所有分頁共用頂部。影片/圖片/批次是「上傳即自動推論」
(media-tab useInferenceStream=uploaded),不需此按鈕,顯示會誤導使用者
以為要先按開始推論。
用 activeTab === "camera" 條件渲染,非 camera 分頁隱藏。純顯示層改動,
handleStart/handleStop/isRunning/disabled 邏輯完全未動;與 handleTabChange
「切走即停」語意一致(切回 camera 時 isRunning 已 false、無殘留)。
reviewer 通過(0C/0M/0m)。tsc/eslint/build/14 test 綠 + 新增 1 測試驗
「按鈕只在 camera 顯示、切走隱藏、切回重現」。
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
2026-08-02 03:38:09 +08:00 |
|
|
|
145ed8e960
|
fix(local-agent): start-agent.sh 補設 VISIONA_CLOUD_ORIGINS(ADR-019 localhost 直連 CORS)
start-agent.sh 漏設 VISIONA_CLOUD_ORIGINS → local-agent CORS 白名單為空 →
影片分頁從瀏覽器打 local-agent 的 preflight 被 403 → 前端判 LOCAL_AGENT_NOT_FOUND
(顯示「需同一台電腦操作」)。
依 MODE 補設雙入口白名單(public: 公網 https + 內網 http;internal 同);
用 ${VISIONA_CLOUD_ORIGINS:-預設} 尊重外部覆寫;啟動 log 印出白名單。
origin 字串與 middleware.go 完整精確比對相容。
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
2026-08-02 03:16:05 +08:00 |
|
|
|
d0ab479a7f
|
fix(local-agent): 影片上傳後推論卡「等待第一筆結果」— WS join 才開播 + late-join replay
時序競態:UploadVideo 回 200 即刻 pipeline.Start() 廣播推論結果,但瀏覽器
200 後才連結果 WS。WP-4 上傳改 localhost 直連(極快)、結果 WS 仍走慢 tunnel
→ 窗口放大;Hub 對無 client 的 room 廣播靜默丟棄 → 早期結果全丟、第一筆永遠等不到。
修法(A2 主修 + B 保險,結果面維持走 tunnel、不動 ADR-019 混合路徑):
- A2:UploadVideo 存檔即回 200,但 pipeline 建好不 Start;背景 gated-start
等 WS join inference:<serial> room 後才 Start;15s 逾時降級照舊開跑(不永久卡)
- B:inference room 緩存最近 30 筆,client join 時先 replay 再收 live
(順帶修 image 模式晚連 WS 丟結果的同類 bug)
- CameraHandler 加 startMu:gated goroutine 的 check-then-act(二次檢查 startCtx
→ Start)與 stop 的 cancel+Stop 原子化,消滅「stop 後 gated 又 Start 舊 pipeline」race
reviewer 通過(Major-1 修復複審 ✅)。14 test -race 全過(含 3000 輪併發 atomicity
測試)、gosec 改的檔 0 新 finding。serial room key 兩端同形已查證排除。
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
2026-08-02 03:16:05 +08:00 |
|
|
|
b73c9b7b7e
|
fix(api): 裝置 detail endpoint tunnel 判定給獨立 3s ctx,修 R-3 誤判離線
裝置 detail endpoint(/api/devices/:id)原用單一 2s ctx,先跑 DeviceRepo.Get
殘餘時間才輪到打 relay 的 store.List → tunnel 狀態查詢逾時被靜默判離線
→ 影片分頁 R-3 誤擋上傳(列表頁 3s 判在線、詳情頁 2s 判離線,同裝置相反)。
修法:tunnel 判定改用獨立 ctx(源自 request context、完整 3s、defer cancel),
與 list 對齊;detail 原 2s ctx 保留給 DeviceRepo.Get。list 也一併改獨立 ctx。
未動 resolveTunnelStatus 的逾時判離線 fail-safe 語意,只給足夠時間。
加可觀測性 log(deadline_exceeded / no-matching / 命中三分支,不含敏感資訊),
供 stage 分辨「真逾時」vs「UserID 比對不中」。前端未動(行為正確)。
reviewer 通過(0C/0M)。build/vet/全套 test 綠 + 3 新 test(含 ctx 完整預算斷言)。
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
2026-07-30 18:18:34 +08:00 |
|
|
|
725ac3cc54
|
Merge pull request #2 from jim800121/feat/adr-019-wp4-video-wiring
feat(adr-019): 影片分頁接線 localhost 直連,上限 90MB→500MB(WP-4)
|
2026-07-30 14:23:48 +08:00 |
|
|
|
b10fbb8091
|
feat(adr-019): 影片分頁接線 localhost 直連,上限 90MB→500MB(WP-4)
影片分頁上傳從舊 tunnel 路徑(/api/media/upload/video + 90MB)切到同機
localhost 直連(取 token → resolveLocalAgent → /api/local/media/upload/video)。
端到端啟用 ADR-019,取代 90MB 過渡限制。
- 新 lib/local-media.ts 編排層:getLocalUploadTicket + uploadVideoViaLocalAgent
- MAX_LOCAL_VIDEO_BYTES=500MB + validateLocalVideoFile(只綁 localhost 路徑;
舊 MAX_VIDEO_BYTES=90MB + tunnel uploadVideo 完全不碰,向下相容)
- R-3 tunnel 離線三層防護:UI disable 不渲染 uploader + ticket 502 + 錯誤映射
- 5 種錯誤 i18n(NOT_FOUND/MISMATCH/離線/401/413)+ AbortError 靜默
reviewer 通過(0C/0M)。tsc/eslint/build 0 error、WP-4 相關 70 test pass。
⚠️ 實機驗證(真序號 hash 同形 fail-closed / PNA / 500MB 大檔實傳 / 混合路徑
結果面)待 stage 部署後驗證。Minor M-1/M-2 留 WP-6 一併處理。
Refs: ADR-019 WP-4。
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
2026-07-30 14:23:21 +08:00 |
|
|
|
329023085e
|
docs(arch): ADR-019 轉 Accepted(實作已 merge,據實標記 WP-4 未接線)
實作經完整審查流程(security 1C+3M → 契約修正 → confirm-only →
逐 WP reviewer → security code-level APPROVED → testing 270 測試全綠)
並 merge(PR #1 / 3eaf3dc)後轉 Accepted。
明確記錄「Accepted ≠ 端到端啟用」:僅底層能力已 merge,WP-4 影片分頁
接線未做,影片仍走 tunnel、90MB 過渡上限仍生效。含兩筆 backlog。
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
2026-07-30 12:53:16 +08:00 |
|
|
|
3eaf3dceb0
|
Merge pull request #1 from jim800121/feat/adr-019-local-direct-upload
feat(adr-019): 影片/圖片/批次上傳走同機 localhost 直連 local-agent
|
2026-07-30 12:50:04 +08:00 |
|
|
|
9031153553
|
feat(adr-019): 影片/圖片/批次上傳走同機 localhost 直連 local-agent
實作 ADR-019 混合路徑:影片/圖片/批次的檔案上傳改由瀏覽器同機直連
local-agent localhost endpoint(繞過雲端 tunnel),控制面 + MJPEG 結果 +
推論 WS 仍走 tunnel。解決大檔頻寬雙倍 + nginx 100M + 300s timeout。
三條 stream(全數過 reviewer + security code-level 複審 APPROVED):
local-agent(Go):
- CORS 雲端 origin 完整精確比對 + Allow-Credentials:false + HostGuard(loopback)
+ PNA header(middleware.go)
- 新 route /api/local/media/upload/*(一律要 token、不看 Origin,關 C1 後門)
- one-time token store(crypto/rand、TTL 120s、綁 deviceId、single-flight consume、
上限 32→429;200 goroutine -race 綠)
- GET /api/local/hello(回 salted SHA-256 serialHashes、最小揭露)
+ POST /api/local/issue-token(Host-based)
- LocalUploadGuard(token+size 驗證放 FormFile 前);video≤500MB / batch 合計 80MB
→ 413;stopActivePipeline + batch 生命週期 temp 檔清理
cloud(visionA-backend):
- POST /api/devices/:serial/local-upload-ticket(OIDC + 裝置歸屬 + 經 tunnel
轉發 issue-token;IDOR-safe、錯誤不洩漏)
frontend(visionA-frontend):
- lib/local-agent.ts(port 探測 3721-3740 並發+快取、Web Crypto serial hash 比對
同機判定、uploadToLocalAgent 通用函式)
- validateBatchFiles 合計大小檢查(MAX_BATCH_TOTAL_BYTES=80MB,消 50×19MB 撞 413 地雷)
回歸:ADR-019 相關 270 測試全綠、既有 tunnel 路徑未被打斷、無 regression。
既有 tunnel(無 Origin)不要求 token(C1 route 分離相容性保證)。
Refs: ADR-019。WP-0(PNA 實機)/WP-4(影片分頁接線)下一批。
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
2026-07-30 12:32:26 +08:00 |
|
|
|
4c962dfec1
|
docs(arch): ADR-019 影片/圖片/批次改走同機 localhost 直連(契約定稿)
新增 ADR-019:影片/圖片/批次上傳從經雲端 tunnel 改為同機瀏覽器直連
local-agent 的 localhost endpoint,修補 design-doc §5.3「大檔不走 tunnel」
原則未套用到 media 的邏輯漏洞。採混合路徑(上傳走 localhost、控制面 +
MJPEG 結果 + 推論 WS 仍走 tunnel)。
已完成 security pre-implementation review(1 Critical + 3 Major)+ architect
依審查修正契約 + security confirm-only 複審 APPROVED。契約含:
- C1: route 分離(新 route /api/local/media/upload/* 一律要 token、不看 Origin),
消除「無 Origin 免 token」後門
- M2: Host header 驗證 = loopback 升為必做(DNS rebinding 緩解)
- M3: CORS 雲端 origin 完整字串精確比對 + Allow-Credentials: false
- 議題1: serial 回 SHA-256(visiona-local-v1‖serial) 雜湊、移除 agentVersion
- M1: media size 上限(video≤500MB / batch 合計 80MB)+ temp 檔清理升為必做
ADR 維持 Proposed,待實作完成 + code-level security 複審後轉 Accepted。
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
2026-07-30 03:31:16 +08:00 |
|
|
|
c595bb8b91
|
fix(frontend): 影片上傳上限 500→90MB 對齊 nginx,解 HTTP 413
stage 推論工作區上傳影片撞 nginx client_max_body_size 100M 回 413,
但前端影片上限標 500MB(af44a9f 只改前端沒同步 nginx)。
過渡修復:MAX_VIDEO_BYTES 調回 90MB,留 10MB buffer 給 multipart
overhead(boundary/header/deviceId 欄位),可靠避開 100M 硬上限。
未來影片改走 localhost 直連(ADR-019)後可放寬此值。
- media.ts:94 MAX_VIDEO_BYTES 500→90MB + 註解說明過渡性質
- media.test.ts 常數斷言 + 邊界 89/90/91MB
- i18n zh-Hant/en 影片 hint 500→90MB
- 模型上傳(500MB)/圖片(20MB)/批次上限未動
Reviewer: Approve(0 Critical/Major/Minor)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
2026-07-26 21:17:39 +08:00 |
|
|
|
9397a4d31f
|
docs: 新增三平台 build troubleshooting 參考
把 M10 這輪三平台 build 踩的雷整理成 troubleshooting 文件,供未來
build 安裝包時參考。
涵蓋 9 條逐項 troubleshooting(統一格式:症狀 → 根因 → 為什麼發生
→ 解法 → 如何根治)、快速症狀索引表、5 條橫向教訓、KneronPLUS
2.0.0 vs 3.1.2 版本相容附錄、build 驗收 checklist。
核心教訓:症狀常不指向根因(Error 12 是 input size、pip 秒退是 wheels
多版本、中文亂碼是 stdio code page),macOS 開發環境測不到大量
Windows-only 問題(編碼、DLL 路徑、SDK 版本差異)。
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
2026-07-24 09:08:13 +08:00 |
|
|
|
f62141a925
|
fix(bridge): Windows 上中文標籤與 log 亂碼
使用者截圖標籤顯示「撣�」而非「布」。實證:布 的 UTF-8 位元組
e5 b8 83 用 cp950 解碼正好得到「撣�」。
根因是 bridge 的 stdio 綁在系統 ANSI code page(繁中 Windows = cp950),
而非 UTF-8。兩個方向的表現不同:
- Go → Python(stdin):Go 的 json.Marshal 不 escape 非 ASCII,送出的是
原始 UTF-8,Python 卻用 cp950 解碼 → 標籤壞掉。這是實際的損壞路徑。
- Python → Go(stdout):json.dumps 預設 ensure_ascii=True 會轉成 \uXXXX,
所以碰巧沒事 —— 但那是巧合不是設計。
同一根因也造成 log 的「(source: declared) �X SDK did not report」,那個
�X 是程式碼裡的 em dash 編碼失敗。
修正兩層,各自不可省:
1. kneron_bridge.py 在 module import 時強制 stdio 為 UTF-8(早於任何 I/O,
import 期間的 traceback 也涵蓋),並在 os.fdopen 明確指定 encoding
—— 那是 JSON-RPC 回應通道,reconfigure() 碰不到它,目前只靠
ensure_ascii 巧合存活。errors="replace" 是刻意的:bridge 崩潰會讓裝置
離線,比一個壞字元嚴重得多。
2. kl720_driver.go 加 PYTHONUTF8=1。實測 PYTHONIOENCODING 只影響 sys.stdin、
PYTHONUTF8 才管得到 os.fdopen 與 locale.getencoding(),單一層都不夠。
Go 端 stdout scanner 不需改(bufio.Scanner 是 byte-oriented,不做轉碼)。
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
2026-07-23 02:00:16 +08:00 |
|
|
|
4f316bb3b8
|
fix: wheels 目錄累積多版本導致 pip 解析失敗,app 啟動失敗
Windows 啟動卡在階段 2,pip 在 2 秒內失敗:
ERROR: Cannot install certifi 2026.2.25 and certifi 2026.6.17
because these package versions have conflicting dependencies.
ERROR: ResolutionImpossible
根因:Makefile 的 vendor-wheels* 用 pip download --dest 但從不清空目錄,
payload-* 複製時也只疊上去不清。upstream 每發一次新版就多留一顆,於是
`pip install *.whl` 同時收到同一套件的多個版本,相依解析器立刻放棄。
vendor/wheels/darwin 目前 16 顆 = 9 個套件 + 7 顆重複舊版,與 log 的
「正在安裝 16 個 Python 套件」完全吻合。
三層修正:
1. ensurePythonRuntime 的 Auto 分支不再丟棄 bundled/system 的失敗原因。
這是使用者連續三輪拿不到線索的原因 —— 它不是根因,是放大器。
pip 的完整輸出本來就在 error 裡,只是被這裡擋掉。
2. selectLatestWheelPerPackage:送 pip 前每個套件只留最新版。這層才救得了
已經出貨的安裝包,只修 Makefile 對使用者手上那包無效。套件名依 PEP 503
正規化,版本用整數逐段比(避免 2.9 > 2.10 的字典序錯誤)。
3. Makefile 新增 clean_wheels_dir(沿用 copy_bundled_data 的路徑防護),
vendor-wheels* 先清再下載、payload-* 複製前先清,從源頭杜絕。
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
2026-07-23 00:55:42 +08:00 |
|
|
|
34bc361527
|
fix(app): Python 相依檢查不得阻斷啟動
上一個 commit 讓 Windows 完全開不了:階段 2 直接失敗,
「python runtime unavailable: no python runtime available」。
根因:健康檢查的 probe 環境與實際跑推論的環境不一致。
`import kp` 在 import 當下就要載入 6 個 native DLL(libkplus / libusb /
libwdi 等),這些不在 Windows 預設搜尋路徑。專案裡每一處真正用 kp 的地方
都自己補了路徑(kl720_driver.go:142 注入 PATH、platform_windows.go:68
用 add_dll_directory),只有新加的 probe 是裸跑 python -c "import kp"。
於是健康的 venv 被判成壞掉 → 重裝 wheels → 用同一個壞 probe 再驗一次 →
仍失敗 → 回 error → 連 app 都進不去。使用者前一天才手動重建好、推論正常
的環境,裝上新版就完全無法啟動。
修正:
- reuseExistingVenv 不回傳 error。venv 存在時的回傳值恆等於舊版
(永遠是 pythonBin, nil),要退化成阻斷版必須改簽章,不會不小心發生
- 首次安裝路徑區分致命與非致命:pip 真的失敗才算致命,probe 沒過就放行
並記 warning
- probe 在 import 前補上 DLL 搜尋路徑,對齊 kl720_driver.go 的實際做法
- 新增 GetPythonDepsWarning binding,讓提示出現在 app 內而非啟動阻斷點
原本要解的「wheels 半套安裝永久卡住」仍然有解,但改為非阻斷:修不好也讓
使用者進到 app 看見具體原因,而不是擋在啟動畫面外。
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
2026-07-23 00:18:13 +08:00 |
|
|
|
f9fbc778be
|
fix: input size 優先序錯誤導致 Windows 推論失敗 + venv 半套安裝永久卡住
## input size 優先序(Windows Error 12 的根因)
先前把使用者手填的 inputSize 排在檔名解析之前,Windows 上 SDK 讀不到
shape 時就用了隨手填的 640x640(模型實際 224x224)→ 推論回
KP_ERROR_INVALID_PARAM。改動前靠檔名 fallback 的 224 反而是對的。
新優先序(可信度由高到低):
SDK > 檔名明確解析 wNNNhNNN > 使用者宣告 > 已知 model id > 寫死預設
檔名排在宣告之前,因為它由編譯工具鏈產生、沒有人為亂填空間;宣告不降到
最底,是因為使用者若刻意填對,仍比無資訊時的預設值貼近現實。
配套:_size_from_name_or_none 讓「真的解析到」與「用了 default」可區分
(舊版兩者回傳型別相同,預設值會偽裝成檔名來源蓋掉宣告值)。
## KneronPLUS 3.1.2 相容
3.1.2 把 shape 搬進巢狀 union,TensorDescriptor 不再有 shape_onnx:
2.0.0 TensorDescriptor.shape_onnx
3.1.2 TensorDescriptor.tensor_shape_info.data → V1 .shape_onnx / V2 .shape
舊碼 getattr 失敗被 except 靜默吃掉,SDK 層在 Windows 永遠落空。現在
兩版都支援,不依賴 enum 版本判斷。
## Error 12 診斷
KP_ERROR_INVALID_PARAM 對使用者無法理解,現在附上當前 input size 與
來源,並針對 declared 來源提示「此尺寸來自手動填寫欄位,請優先確認」。
原始錯誤保留不吞。
## venv 半套安裝
app.go 原本只檢查 python.exe 存在就跳過安裝,導致 wheels 裝到一半中斷
後每次啟動都跳過、永遠卡住且無提示,使用者必須手動刪整個 runtime 目錄。
改為比對 wheel 清單指紋(快路徑不啟動 process),不符才實跑
import kp/numpy/cv2 驗證,失敗則只重跑 wheels 安裝。標記檔僅在 pip 成功
且 import 驗過後才寫入,不留「已就緒」假象。
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
2026-07-22 23:41:19 +08:00 |
|
|
|
a05d206c07
|
fix(build): copy_bundled_data 改為冪等,清掉前次 build 的殘留
Windows/Linux build 卡在「預期 2 個 .nef,實際 8 個」。
payload-macos 呼叫前有 rm -rf payload/darwin,但 payload-windows 與
payload-linux 刻意不清(build-server-* 已先把 binary 放進 bin/),
導致 data/ 留著白名單機制加入前那 8 個 .nef,與新複製的 2 個相加後
觸發後置檢查。
後置檢查本身是對的 —— installer/windows/visiona-local.iss:86 是
recursesubdirs 整包收,殘留什麼就出貨什麼。問題在 helper 不冪等。
改為複製前先清空目標 data 目錄。清整個目錄而非只清 nef/,因為該目錄
內容全由此 helper 產生,只清 nef/ 無法處理未來移除非 nef 檔案的情況。
rm -rf 加四層防護:拒絕空值、絕對路徑與 ~、含 .. 的跳脫、不符
payload/*/data 格式的目標,另檢查目標不是檔案。用 case 而非 [[ ]]
以相容 Git Bash。
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
2026-07-22 22:15:26 +08:00 |
|
|
|
61593f004d
|
fix(build): bootstrap-windows 讓 MSYS2 bash 找得到 Go / wails / node / pnpm
Windows build 卡在 `go: command not found`,但 PowerShell 端 go 明明可用。
原因是腳本用 `bash.exe -l` 呼叫 make,login shell 會 source /etc/profile
重建 PATH,而非繼承 Windows 的。`MSYS2_PATH_TYPE=inherit` 只對 MSYS2
自己的啟動器有效,直接呼叫 bash.exe 時不生效。
腳本原本就為 Inno Setup 與 Python 手動 export 路徑,只是漏了這四個工具。
現在比照辦理:
- 新增 Find-ToolDir,先用 Get-Command(可找到自訂磁碟的安裝),
找不到再退回已知安裝位置,都失敗則明確 Fail 並附安裝指引
- wails 路徑改問 `go env GOPATH` 而非假設 %USERPROFILE%\go,
且用 go.exe 絕對路徑呼叫(否則在本 bug 情境下自己也會找不到 go)
- pnpm 獨立偵測,npm i -g 的安裝位置與 node 不同
- 各目錄個別加雙引號後以 : 串接,避免 Program Files 的空白被斷詞
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
2026-07-22 21:30:31 +08:00 |
|
|
|
a7bc67baba
|
chore: ignore .autoflow / .mcp.json / graphify-out
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
2026-07-22 19:27:45 +08:00 |
|
|
|
744283bd28
|
feat(build): 安裝包只打包指定模型並改用中文名稱
安裝包從 8 個 .nef 縮減為 2 個,models.json 保留完整定義以便日後
加回。
- Makefile 加 BUNDLED_NEFS 白名單,三平台共用 copy_bundled_data
helper;用 POSIX find/cp 而非 rsync(Windows CI 的 Git Bash 沒有
rsync)
- 白名單檔案不存在時 build 直接失敗,並在複製後驗證 models.json
存在且 .nef 數量相符 —— 避免產出「安裝後 0 個模型」卻回報成功
- FCOS Detection (KL520) 改名為「物件辨識」
- Tiny YOLOv3 (KL520) 改名為「人型監測」
(只改 name/description,id 不動以免影響既有設定與紀錄)
- Repository 啟動時過濾 .nef 不存在的模型,否則使用者會看到未打包
的模型並在選取後拿到莫名錯誤
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
2026-07-22 19:27:40 +08:00 |
|
|
|
5c1c37d151
|
feat(frontend): classification 結果呈現與推論期控制項
detection 畫框、classification 改在影像右上角疊標籤(不畫框),
並在推論面板提供即時切換解析方式與上傳 label 檔。
- 新增 InferenceOverlay 依 taskType 分派;ClassificationOverlay 用
DOM 而非 canvas,讓 CJK 排版與 aria-live 交給瀏覽器處理
- 標籤防閃爍:挑戰者需連續 3 幀居冠才切換,或信心度領先 15% 直接切;
低於門檻立即清空(顯示過期標籤比空白更糟)
- 身分比對優先用 classIndex,避免換 label 檔時被誤判為換類別
- 推論設定卡片:即時切 detection/classification、上傳 .txt label、
清除 label,皆不需重燒
- classification-result 原本無條件渲染,導致 detection 模式下側欄
永遠顯示「分類結果」與空圖表,改為依 taskType 切換
- 清掉 camera-overlay 每幀執行的 debug console.log
- 補 ResizeObserver stub,原本任何渲染 InferencePanel 的測試都會
在 jsdom 直接拋錯
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
2026-07-22 19:27:28 +08:00 |
|
|
|
4583406efa
|
feat(api): 推論期切換解析方式與上傳 label 檔
新增 POST /api/devices/:id/inference/options,讓已燒錄的模型不重燒
即可切換 detection/classification 與更換 label。
KL520 一次只能載一個模型(換模型必須重燒),但解析方式與 label 都
只是後處理與顯示層,不碰 NPU,因此可即時生效。
- JSON: {taskType?, labels?};multipart: taskType + labelFile
- 欄位用指標型別以區分「省略 = 不動」與「labels:[] = 清空」
- label 解析器(internal/labelfile):格式 <index> <名稱>
略過空行與 # 註解、trim CRLF、名稱含空白只 split 第一個空白、
index 非整數/負數/重複則整檔拒絕並回報行號、稀疏 index 補空字串
- index 上限 4095、檔案上限 256KB,防記憶體耗盡
- 非法 taskType 一律拒絕(含舊別名 detection),因為 bridge 對無法
辨識的值是靜默 fallback,忽略會回 200 但用錯解析方式
- 走窄能力介面 InferenceOptionsDriver,不動 DeviceDriver 簽章
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
2026-07-22 19:27:16 +08:00 |
|
|
|
ddd1aae5d1
|
feat(server): 把 model metadata 傳進推論鏈路
models.json 宣告的 taskType/labels/inputSize 原本在 flash 時被丟棄
(只傳 modelPath),導致 bridge 只能靠檔名猜測模型類型與尺寸。
- FlashOptions 帶 TaskType/Labels/InputWidth/InputHeight
- 抽出 buildLoadModelCommand,四處 load_model 呼叫點(初次 + 三條
retry 路徑)統一走它,並加測試釘住呼叫點數量與「不得有手寫 payload」
—— 讓漏改 retry 路徑在結構上不可能發生
- ClassResult 加 ClassIndex(不加 omitempty,index 0 是合法值)
用 FlashOptions struct 而非裸參數,未來擴充欄位不需再動 interface
與所有 test fake。
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
2026-07-22 19:27:02 +08:00 |
|
|
|
f14d24bd7b
|
feat(bridge): classification 自適應解析 + 推論期動態切換
新增 classification 推論支援,核心是「不預設模型長相」:
- output shape 自適應:支援 (1,C)/(C,)/(1,C,1,1)/(C,1,1)/(1,1,1,C)
及任何 squeeze 後為一維的張量;類別數從 shape 動態取得,
移除原本寫死的 num_classes=1000
- 無法解析時明確報錯(附實際 shape),不靜默回空結果
- logits vs 已 softmax 自動偵測:sum≈1.0 且全非負才跳過 softmax
(容差 1e-4,實測 float32 softmax 偏差最大僅 ~4e-7)
- label 為純顯示層:有注入用 label、沒有則輸出原始 enum class_N
- input size 三層來源:SDK > 宣告值 > 檔名猜測,log 標示來源
- 新增 handle_set_inference_options:不重載模型即可改解析方式與 label
修正:
- _detect_model_type 改為外部指定優先,解決未知檔名被誤判成
tiny_yolov3 而回傳空結果的根因
- handle_disconnect/reset 未清 label 狀態,導致換模型後沿用舊 label 表
- load_model 失敗路徑會污染全域 metadata,改為 defer-until-success
- taskType 值域統一為 object_detection(原本回 detection)
- 檔名解析原本只取 width 丟棄 height,非正方形模型會被壓成正方形
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
2026-07-22 19:26:51 +08:00 |
|
|
|
af44a9f9ba
|
feat(frontend): flash 完成工作區入口醒目化 + 影片上限 200→500MB
驗收後兩個 UX 微調:
- flash 載入模型完成後「開啟工作區」入口不明顯、使用者要自己找 → Button
改 size=lg + ArrowRight 前往圖示 + ring-primary/40 highlight(設計系統
token、不裸色碼)。保留手動導航(點擊才去、無自動 router.push)、serial
空 disable + 離線 disable gate 維持
- 影片上傳上限 MAX_VIDEO_BYTES 200→500MB + i18n 兩語系 hint 文案。影片
upload timeout 本來就是 0(不限、後端決定)→ 500MB 不會撞 timeout
Reviewer 通過(0C/0M/0Mi/1Sug、timeout 獨立驗證、i18n 無殘留 200MB)。
tsc/eslint 0、vitest 39 passed(499/500/501MB 邊界 mock size 無 OOM +
醒目化樣式/行為)、next build 0。
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
2026-07-21 01:17:11 +08:00 |
|
|
|
67737334c8
|
fix(device): GET /api/devices/:id proxy 拿即時 driver status(方案 Y-2,解載入模型 disabled)
問題:連線後裝置詳情頁連線狀態顯示 unknown、載入模型按鈕永遠 disabled。
根因=雲端 GET /api/devices/:id 是純 DB 讀、沒 proxy 到 local agent → DB 只有
tunnel 層 status(online/offline/unknown)、沒有 driver 七態(detected/
connected/...)→ 前端 gate isDriverConnected 永遠 false。(上輪 C1/C5 查證
假設 status 拿得到、沒追到寫入點的漏洞)
修法(方案 Y-2、local agent 零改、gate 零改):
- backend device_driver_status.go(新):driverStatusFetcher 介面 +
forwarderDriverStatusFetcher(走既有 session.Forwarder proxy)+ envelope 解析
- devices.go devicesGetHandler:讀 DB metadata 後,device 有序號時額外 proxy
打 local agent GET /api/devices/{serial}(serial 路由對齊 WP-C)拿即時 driver
status 覆蓋 USBStatus;remoteStatus/tunnel_online 保留(offline banner 不壞)
- graceful fallback(全回 200 不掛 500):無序號/tunnel 離線/不可達/timeout/
非2xx/success:false/空status/Forwarder未配置 → 保留 DB status + Debug log
- 2s 短 timeout(不拖詳情頁)、serial path url.PathEscape 防禦
- frontend:DeviceHardwareStatus 加 unknown + coerceHardwareStatus(非七值→
unknown)+ normalizeDevice fallback disconnected→unknown(修誤顯未連接)+
i18n devices.status.unknown 兩語系(未確認/Unknown)
Reviewer 通過(0C/0M/3Mi/2Sug、Y-2 10/10、端到端追證 gate 放行 + 8 fallback
分支無一掛 500)。backend 8 測試 + frontend 49 passed、build/vet/test 綠、
gitleaks 0。端到端「即時 connected 覆蓋 unknown」需在線 agent+登入實測(單元
測試已覆蓋合併+fallback)。
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
2026-07-17 09:25:26 +08:00 |
|
|
|
1da385f345
|
feat(frontend): 裝置詳情頁連線/斷線按鈕 + 兩步式 gate(解載入模型 device not connected)
問題:device 配對後停在 detected(rescan 偵測到硬體但沒 connect driver),
載入模型被 flash service IsConnected() 擋成 400。根因=前端漏了「連線」按鈕
(POC 有、移植時當 local-tool 專屬刪掉、詳情頁沒補回雲端版)。前端誤用
remoteStatus=online(tunnel) 當 flash 門檻,≠ device driver IsConnected()。
修法(方案 A、兩步式):
- device-detail-client.tsx:連線/斷線按鈕 + 三分支 gate(未連線→連線鈕/
連線中→loading disabled/已連線→斷線鈕+載入模型可用)+ driver status 呈現
- connect 走 serial(對齊 WP-C)、成功後 fetchDevice(UUID) 刷新(C4 混合模型,
WS 推送因 backend 501 stub 不通故用輪詢)
- 60s connect UX:loading hint「首次連線需載入韌體約1分鐘,請勿關閉頁面」
- FlashDialog gate 收緊 disabled !isOnline → !isOnline || !isDriverConnected
- device-store connect 的 api.post 加 timeoutMs:130_000(全域 30s < connect
最壞 65s,單點覆寫;> local agent 120s ctx)
- i18n devices.connect.* 13 key 兩語系
- TDD §10.5.1 過時型別修正 + 新增 §10.5.1.1 two-step connect 流程
推論線一併解決:能進 workspace 的裝置必已 connect(原無 IsConnected 檢查
會靜默空跑無框)。
Reviewer 通過(0C/0M/2Mi/3Sug、規格 12/12、gate 三分支全組合走查)。
tsc/eslint 0、vitest 44 passed、next build 0。
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
2026-07-16 15:30:33 +08:00 |
|
|
|
fac07c39d0
|
fix(local-agent): 配對前自動 rescan USB,解序號偵測時序問題
問題:配對時 exchange 撈 GET /api/devices(ListDevices=讀快取、不重新
偵測)。若 agent 啟動時 USB 尚未插入/未偵測到,快取為空 → 配對撈不到
序號 → payload 不帶 devices → 雲端裝置「尚未回報序號」,即便之後插上
USB 也不會自動重偵測。
修法(方案 A、最小侵入):
- NewLocalDeviceLister 改打 POST /api/devices/scan(ScanDevices →
Manager.Rescan() 重新偵測 USB),配對前強制重掃一次
- localDeviceListTimeout 2s → localDeviceScanTimeout 8s(真 SDK scan
kp.core.scan_devices 較慢、給餘裕,逾時走 fallback 不卡配對)
- app.go DeviceLister 注入註解同步更新(Reviewer Mi-1)
不變量保留(Reviewer 獨立驗證):
- rescan 失敗/逾時 → lister return nil(不 error)→ payload omit devices
→ 配對照常(序號是加值資訊,不中斷配對)
- Rescan 對序號身分未變的 session 保持連線(serialIdentity 相等 continue)、
只斷被拔除的 → 不誤斷在線 tunnel/inference session
- Pair 由 lifecycleMu 序列化、Rescan write lock 全量重建 → 重試冪等安全
Reviewer 通過(0C/0M/1Mi/2Sug)。兩 module build/vet/test/race 全綠、
8 個新 tunnel 行為測試 PASS(端到端快取空→rescan→序號進 payload +
逾時 fallback)、gitleaks 0。
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
2026-07-16 15:02:31 +08:00 |
|
|
|
fc7e1e0bc1
|
fix(local-agent): 修 vendor wheels 多版本累積導致 SDK 沒裝進 bundled runtime
根因:Makefile vendor-wheels 用 pip download --dest 只加不清空,跨多次
vendor-sync 累積出同套件多版本(certifi 三版/numpy 二版等共 17 wheel)→
agent bootstrap 的 ensureBundledPython 把目錄所有 .whl 當獨立參數丟 pip
install → 版本衝突 ResolutionImpossible → pip 失敗 → venv 建了但空 →
無 Kneron PLUS SDK → bridge scan 走 pyusb fallback 回假序號 0x00000000 →
裝置「尚未回報序號」+ 載入模型 device not connected。
修法(3 個 vendor-wheels target):
- 開頭 rm -f vendor/wheels/<plat>/*.whl 清空,確保每次 sync 單版本
- 結尾 dedup 驗證(sort|uniq -d 偵測多版本 → exit 1 fail-fast)
- linux 補「無專屬 KneronPLUS wheel 時退回複製 macos py3-none-any」
- .gitignore 補 local-agent/vendor|payload|dist 對稱規則(保留 ffmpeg
binary + .gitkeep 例外),防 vendor-sync 後 git add -A 撈進 build 產物
決定性 evidence(agent 實際 bundled runtime):清空 runtime → 起剛 build
的 .app → agent 自己 bootstrap 裝 9 個乾淨單版 wheel(修前 17 含重複必失敗)
→ venv 有 kp → GET /api/devices 回真序號 0xB906162C(非 0x00000000)。
Reviewer 通過(0C/0M/4Mi/3Sug)。win/linux 同邏輯已補、未在對應 runner
驗證(已知限制)。follow-up:ensureBundledPython 列舉 wheel 脆弱設計建議
改 find-links 自解析(backend 另案)。
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
2026-07-16 14:21:08 +08:00 |
|
|
|
51dfd0f2d8
|
fix(frontend): normalizeDevice serialNumber 加 trim(WP-C Minor #1)
純空白字串(" ")原判 truthy → 會以空白 serial 組出必失敗的請求路由。
改為先 trim 再判定:serial !== "" ? serial : null。順帶消除字面 "0"
被 falsy 誤判為 null 的隱性行為。補純空白 → null 邊界測試。
Reviewer 通過(0C/0M/0Mi)。tsc/eslint 0、18 test 綠。
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
2026-07-16 11:40:35 +08:00 |
|
|
|
26b433eb10
|
fix(local-agent): review follow-up 小批(TLS Mi-3/4 + WP-0 S-3/4)
- Mi-3: insecure Transport 改用 DefaultTransport.Clone() 只覆寫 TLSConfig
(保留 proxy/timeout,消除「開 skip 順便改掉 proxy 行為」副作用)
- Mi-4: exchange 200 分支檢查 Success 欄位(避免 200+success:false 落到
誤導性的 missing session_token;既有回歸測試改用直接斷言防護不減反增)
- S-3: collectLocalDevices 全空 serial 濾掉不送 devices 陣列(payload 對稱)
- S-4: 假序號比對統一用 EqualFold(防未來 bridge 輸出 casing 變化)
Reviewer 通過(0C/0M/1Mi/3Sug)。兩 module build/vet/test + -race 綠、
gitleaks 0、TLS 行為級測試全 PASS。
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
2026-07-16 11:40:35 +08:00 |
|
|
|
59c57fa481
|
feat(device): WP-B repository 接 agents 模型 + exchange 重塑(A' 走向第二階段 Go 層)
- Device struct 加 4 欄(agent_id/agent_local_device_id/registered_at/
is_representative)+ deviceColumns 13→17 + scanDevice/SaveTx 讀寫新欄
- 新增 internal/agent package(domain + interface + in-memory + PG repo):
GetOrCreateAgentTx/GetByOwnerTx,advisory lock 序列化同 owner get-or-create
- exchange 重塑:建/復用 agent → representative device(綁 session_tokens、
serial=NULL)→ loop 建 N 顆真 USB device(R1 完整 N 顆非只第一顆)
- List filter is_representative=false + DeviceListItem 回傳 agent_id/registered_at
- 併入 WP-0/0005 follow-up Minor:Mi#2 lost-update 收斂(tx 內查詢+局部更新)
/ Mi#3 過時註解 / Mi#4 空 serial 回 ErrNotFound / Mi#5 serial 白名單
^0x[0-9A-Fa-f]{8}$ + 去重 / S-1 firmware forward-compat / S-2 device Name 衍生
守 ADR-018 A'(一 owner N agents、session_tokens FK 物理不動、不加 owner
unique 為多機器留路)。Reviewer 通過(0C/0M)。5 套件 dbtest 130 全綠
(db 19/device 37/agent 13/api 172/cmd 60)、build/vet/test 綠。
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
2026-07-16 11:40:17 +08:00 |
|
|
|
8369cab85c
|
feat(db): migration 0005 agents 模型(個人設備管理 A' 走向第二階段地基)
- 新增 agents 表 + devices 加 4 欄(agent_id/agent_local_device_id/
registered_at/is_representative)+ 2 index + 純 SQL data migration
- data migration 採 R-A:agent.id := device.id 決定性推導、冪等、
soft-deleted device 排除(WHERE deleted_at IS NULL)
- 守住 ADR-018 走向 A':不碰 session_tokens FK、不改現有 partial
unique index uq_devices_owner_serial_active、對 0001-0003 零破壞
- migrate_0005_db_test.go 6 個 dbtest case(apply/data migration/
rollback 對稱/re-apply 冪等/session_tokens 零影響/既有 device 讀寫回歸)
- 修 TestMigrate_UpDownUp 編號 gap 假設(0001/2/3/5 無 0004):
assert.Equal(topVer-1) → assert.Less(downVer, topVer)
- .gitignore 加 .logs/ + **/.logs/(本機執行 log per-branch 不進 git)
Reviewer 通過(0 Critical/0 Major/3 Minor/4 Sug)。全 db package 41
dbtest 130 綠、build/vet/test 綠、gitleaks 0。
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
2026-07-16 04:05:53 +08:00 |
|
|
|
72544d00ba
|
docs(adr): ADR-018 §8 addendum — C5 實作偏差回填(路由段維持 UUID)
- §5.5 加補註指向、原文一字未動(ADR 不可變原則)
- §8.1 記錄 C5 偏差證據鏈(fetchDevice 純 DB / API 無 GetBySerial /
帶 serial deep-link 必 404)與最終實作(路由段 UUID、serial 頁內派生、
入口 disable 全落實);決策本體 FE-A 與 C1–C4/C6–C8 不變
- 裁定來源:wp-c-frontend-serial-routing-review.md(reviewer 獨立驗證)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
2026-07-11 08:39:32 +08:00 |
|
|
|
12f5bf6c47
|
feat(frontend): WP-C serial 路由落地(ADR-018 FE-A 混合模型)
- DeviceSummary 加 serialNumber(serial_number/serialNumber 雙 key 容錯、
缺欄/空字串 → null)
- 五個 proxy 操作識別值換 serial:connect/disconnect、flash POST+進度 WS
(單一派生點保 room key 一致)、inference WS、camera start/stop+WS、
media 三 upload
- serial 為空全面 disable + 提示(workspace banner/media 占位/flash-dialog/
device-card tooltip/device-detail 兩鈕+序號 InfoRow/選擇頁);i18n 兩語系
- UUID 組維持:fetchDevices/fetchDevice/unpair/詳情頁路由
- C5 偏差(路由段維持 UUID):與 FE-A 定案一致、reviewer 獨立驗證成立
(API 層無 GetBySerial、帶 serial deep-link 必 404);文件回填另派
- evidence:tsc 0 / eslint 0 / next build 15 route / 觸及 11 測試檔 99 passed
- review:通過 0C/0M/3Mi/2Sug(.autoflow/05-implementation/review/
wp-c-frontend-serial-routing-review.md)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
2026-07-10 09:58:52 +08:00 |
|
|
|
12b1fe3bad
|
fix(local-agent): Rescan 序號身分比對替換 stale session + 鎖外 Disconnect
- serialIdentity() 三態比對(空/假序號 0x00000000 正規化為無身分、對齊
ADR-018 R2):Rescan 對既存合成 ID 比對身分——同一顆保留 live session、
換位/拔插以新 info 替換 session,serial 索引重建即正確
- stale drivers 改釋放鎖後 Disconnect(不再阻塞 GetDevice 路由)+
Disconnect 錯誤改 WARNING log
- 測試 seam:detectFn/newDriverFn 注入 + newSessionDriverLocked 統一建構
(Start 行為零變動);新 4 支行為級測試(拔除位移/換位 rebind/
同序號保 session/無身分回歸)
- evidence:build/vet/test 全綠 + -race ok;review 通過 0C/0M/0Mi/4Sug
(wp0-serial-routing-review.md「Minor #1 修復審查」章節)
- WP-C 阻擋項解除;觀察項:多裝置實測留意 changed identity log
(偵測順序抖動時解法在 detector 端排序)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
2026-07-10 09:44:47 +08:00 |
|
|
|
b9ee184586
|
feat(device): WP-0 序號串通 + serial 路由(ADR-018 走向 A' 第一階段)
- local-agent/server:detector 保留 kn_number(parseScanDevices 可測化、
合成 ID 語意不動)+ DeviceInfo.SerialNumber + Manager serialToLocalID
反查表 + GetDevice 雙查(sessions 先、serial 後,純加法)
- visiona-agent:pairing exchange 帶本地裝置清單(DeviceLister 失敗不中斷
配對、timeout 2s、omitempty 舊版相容)
- visionA-backend:exchange 收 devices —— R1 取第一顆可用序號、R2 假序號
0x00000000 寫 NULL、R4 同 owner 同序號復用既有 device_id(防 23505)、
pg+mem 兩實作對齊
- 五個 proxy 操作(flash/inference/camera/connect/disconnect)收斂於
GetDevice 單一入口,serial 路由一處涵蓋
- docs:api-spec.md §2 增補 POST /api/pairing/exchange(schema + R1/R2/R4)
- 測試:行為級四環節鏈 + dbtest 130 實跑 6/6 + DBOn 回歸 4/4;
三 module build/vet/test 全綠
- review:通過 0C/0M/6Mi/5Sug(.autoflow/05-implementation/review/
wp0-serial-routing-review.md);Minor #1 Rescan stale session 掛 WP-C 前置
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
2026-07-10 09:31:51 +08:00 |
|
|
|
3d30fdc580
|
feat(local-agent): TLS skip opt-in for self-signed stage + exchange envelope 對齊
- 新增 VISIONA_INSECURE_SKIP_TLS_VERIFY(DEV/TEST ONLY、須明確 opt-in "true"):
pairing exchange HTTP client、tunnel WSS dialer、設定頁 TestConnection 三路徑
共用 TLSConfigForDial(含 ALPN 釘 http/1.1);NewApp 唯一 env 讀取點注入欄位
- exchangeResponse 對齊雲端 /api/pairing/exchange success envelope
(account/relay_url 選填 fallback 保留、舊頂層格式回歸防護)
- .gitignore:.env.stage* + !.env.stage.example + *.pptx(堵 secrets 誤入)
- start-agent.sh(新增):public 模式 export skip env + 預檢 curl https 帶 -k
- 測試:自簽 TLS server 行為級(預設拒絕驗 x509 / 開啟通過)+ opt-in 規則
11+5 案例 + TestConnection 3 測試;go build/vet/test 3 packages 全綠
- review:2 輪通過(.autoflow/05-implementation/review/tls-skip-uncommitted-batch-review.md)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
2026-07-10 09:01:10 +08:00 |
|
|
|
276910854e
|
docs(adr): ADR-018 一 agent 多 device 模型 + serial 路由(走向 A')
個人設備管理資料模型決策,使用者裁決 Accepted。
- 走向 A':新增 agents 表 + devices 改實體 USB 掛 agent_id +
session_tokens.device_id 保留物理 schema 改綁代表 device(避開破壞性
FK migration)+ 路由統一用 serial(kn_number) + local agent serial 反查
雙查(純加法、保護剛做完的推論)
- 前端 FE-A 混合:DB 操作用 UUID、路由到 local agent 操作用 serial、
serial 空的 device 路由操作 disable
- 關鍵論證:推論路由不經 session_tokens.device_id(proxy pickActiveSessionToken
按 userID),單一 FK 非硬傷;真缺口是 UUID↔local key 未對齊
- migration 0004(序號、無 DDL 可先交付)+ 0005(agents 模型)
替代方案(mapping 版 A/B、FE-B)與否決理由、R-Route 查證結論已併入 ADR。
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
2026-07-09 08:39:27 +08:00 |
|
|
|
4f50ad7350
|
feat(ws): flash-progress WS tunnel proxy(後端,載入模型進度回顯)
flash「載入模型到裝置」後端缺口:flash-progress WS 從 501 stub 換真
tunnel proxy,複用 inference WS 的 path-agnostic handler。
- camera.go registerWebSocketRoutes:加 /ws/devices/:id/flash-progress
(複用 newWebSocketProxyHandler、掛 wsAuthGroup same-origin cookie)
- stubs.go:刪 flash-progress 501 stub(成對防 radix panic)+ 更新註解
- api.go:更新 wsAuthGroup 註解(現含 inference + flash-progress 兩條裝置級 WS)
- camera_ws_test.go:+3 test(NoForwarder/TunnelDisconnected/CoexistsWithInference)
- all_endpoints_require_auth_test.go:收窄白名單,flash-progress 從 skipped→
covered 納入「無 cookie 應 401」回歸檢查(守得住證明:移除 auth 即 FAIL)
契約:WS /ws/devices/:id/flash-progress、payload raw {percent,stage,message?,error?}
透明轉發。Reviewer 0C/0M/1Mi 通過(Mi 註解已修)。build/vet/全回歸綠。
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
2026-07-09 06:30:36 +08:00 |
|
|
|
051994ed54
|
feat(workspace): 圖片/影片/批次推論 tab + 載入模型到裝置 FlashDialog(前端)
推論工作區前端塔3 + flash 前端(i18n/device-detail 交纏、一批 commit)。
塔3(圖片/影片/批次 tab、複用塊1/2 顯示管線 0 重造):
- media.ts 上傳 helper(XHR image/video/batch)+ media-uploader + media-tab
- workspace-client 3 tab 打開 + activeTab 互斥 camera/media WS
- video seek 用後端 durationSeconds 換算(脫離 fps 耦合、Reviewer M-1 修正)
- 補 tab 切換 WS reset 測試(S-1)
- Reviewer 2 輪通過
flash 前端(載入模型到裝置、補「進工作區前置」缺口,照 POC 移植):
- flash-dialog + flash-progress(選 model + 相容性檢查 + WS 進度)
- flash-store(throw-based ApiError)
- use-flash-progress(onOpen 才 POST 防 race + hasStartedRef 防重連重複)
- hardware-compat(targetChip 單值、寧鬆勿嚴、UX 警示非安全閘)
- device-detail-client 掛 FlashDialog(gate 未改、flash 完 fetchDevice 解鎖)
- Reviewer 0C/0M
契約:same-origin cookie、WS/stream/upload URL 相對路徑無 token、i18n 雙語對稱、
設計 token 不裸色值。全前端 tsc/eslint clean、塔3 30 test + flash 45 test 綠。
(全套 11 failed 全屬 conversion-store 既有 flaky、未觸碰)
follow-up:flash WS 逾時提示(Mi)、--success token(design)、conversion-store flaky 釐清。
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
2026-07-09 06:27:14 +08:00 |
|
|
|
81a32a5bf8
|
feat(stage): nginx 加 /ws/ location(推論 inference WS + 其餘 /ws/* stub)
兩個 server block(公網 stage-9527 + 內網 IP 直連 192.168.0.130)各加
一條 location /ws/ → proxy_pass api-server(:3721)。缺這條時 /ws/* 會落到
catch-all → Next.js → 404,擋住前端推論頁 WS 握手。
- WS upgrade 三要素(http/1.1 + Upgrade + Connection $connection_upgrade)
- 長 timeout 86400s + proxy_buffering off(比照 /tunnel/connect)
- 不影響既有 /tunnel/connect(不同 path 前綴、互不 shadow)
- 兩 block header 對齊(含 X-Forwarded-Host)
驗證:/ws/devices/test-id/inference 不帶 cookie → 401(過 backend auth)
不再 404;/tunnel/connect 回歸 401;preset 下載 200/206;demo 設定保留。
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
2026-07-09 06:00:59 +08:00 |
|
|
|
0010cc35c3
|
feat(workspace): canvas overlay 疊 bbox + WS 即時推論面板(前端塊2)
推論工作區前端塊2:canvas overlay 疊在 MJPEG <img> 上、接 WS
inference:<deviceId> 推的 raw InferenceResult、即時繪 bbox+label+信心度;
右側 Inference panel 從 Phase 1 佔位換成 WS 即時結果清單 + FPS/延遲。
照 edge-ai-platform POC 移植(唯讀參考)。
- camera-overlay.tsx:normalized bbox→canvas 像素換算、label 框
- inference-panel.tsx:指標 + 清單 + aria-live 無障礙
- inference-store.ts:fps/avgLatency、MAX_RESULTS=100 上限
- use-inference-stream.ts:用既有 useWebSocket(same-origin cookie、無 token URL)
- workspace-client:overlay 塞 CameraFeed slot、訂閱 WS(僅 isRunning && isOnline)
canvas 顏色讀設計 token(--chart-*/--background,getComputedStyle 快取、
主題切換才重讀)、跟隨深淺主題、不裸色值。
Reviewer 2 輪通過(0C/0M)。修正:
- M1 overlay 座標錯位:feedSize 初值 null、未拿真實顯示尺寸不繪(MJPEG 非
4:3 不錯位)
- M2 效能 jank:palette 快取 useState + MutationObserver 主題切換才重讀
(不再每 frame getComputedStyle)
- m2 label fallback 色改實際色(canvas 不認 currentColor)
- m3 isValidBBox guard:壞 payload 略過不 crash
+6 新測試(M1 640×360→height=360、M2 呼叫數不增、m3 NaN/undefined 略過)。
tsc/eslint clean、塊2 範圍 37 test 綠。(全套 11 failed 全屬 conversion-store
既有 time-based flaky、未觸碰)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
2026-07-09 05:03:35 +08:00 |
|