# BUG: PATCH /blocks/:id 回 403 "block belongs to different org"(同一把 key 能 create/get/delete 卻不能 patch) > 回報日期:2026-05-29 > 回報來源:arcrun Phase 2(把 kbdb_* 零件降級成 recipe,逐個驗收時發現) > 嚴重度:中高 —— PATCH endpoint 對「自己剛建、且能刪的 block」拒絕更新,等於 update 能力全壞 > 影響:任何「查→改」或 upsert 流程(先 GET 找到 block,再 PATCH 更新)都無法完成 --- ## 症狀 用**同一把 API key**、對**同一個 block**,四個操作的結果不一致: | 操作 | endpoint | HTTP | 結果 | |---|---|---|---| | 建立 | `POST /blocks` | **201** | ✅ 建出 block,回 id | | 讀取 | `GET /blocks/:id` | **200** | ✅ 讀得到 | | **更新** | **`PATCH /blocks/:id`** | **403** | ❌ `{"error":"block belongs to different org"}` | | 刪除 | `DELETE /blocks/:id` | **200** | ✅ `{"deleted":true}` | **矛盾點**:同一把 key 能 create / get / delete 這個 block —— 代表 KBDB 認定我擁有它(org 一致)。但 PATCH 卻說「belongs to different org」。**create 寫進去的 org 判定,和 patch 讀出來比對的 org 判定不一致**,這是 KBDB 內部 org 歸屬邏輯的 bug。 ## 重現(裸 curl,不經 arcrun) 為排除是 arcrun 注入問題,直接用裸 curl + Bearer token 打 `https://kbdb.finally.click`: ```bash TOKEN="Bearer ak_402d…" # 同一把 key,全程不變 BASE=https://kbdb.finally.click # 1. 建立 → 201 curl -X POST $BASE/blocks -H "Authorization: $TOKEN" -H 'Content-Type: application/json' \ -d '{"content":"...","type":"note","page_name":"kbdb_bug_repro","source":"...","user_id":"arcrun_phase2"}' # → {"id":"f39ea877-...","action":"created"} HTTP 201 # 2. 讀取 → 200 curl $BASE/blocks/f39ea877-... -H "Authorization: $TOKEN" # → HTTP 200 # 3. 更新 → 403 ★ BUG curl -X PATCH $BASE/blocks/f39ea877-... -H "Authorization: $TOKEN" -H 'Content-Type: application/json' \ -d '{"content":"patched"}' # → {"error":"block belongs to different org"} HTTP 403 # 4. 刪除 → 200(證明我擁有此 block) curl -X DELETE $BASE/blocks/f39ea877-... -H "Authorization: $TOKEN" # → {"deleted":true} HTTP 200 ``` 經 arcrun(cypher-executor → auth_static_key 注入同一把 token → recipe 轉發)也是完全相同結果,所以**確定是 KBDB server 端 PATCH 路徑的問題,不是 client / arcrun 的問題**。 ## 推測方向(給 KBDB 排查) create / get / delete 的 org 判定路徑,和 PATCH 的 org 判定路徑不一致。可能: 1. **PATCH 用了不同的 org 解析來源**:例如 create 用 token → org_id 的某種映射寫入 block,但 PATCH 的 org-check 從另一個欄位 / 另一張表讀,兩邊算出的 org 不同。 2. **block 落地時的 org_id 與 token 的 org_id 不一致**:create 時可能用了 default org 或 null org 寫入,PATCH 的 ownership 檢查卻嚴格比對 token org,導致「自己建的卻不是自己 org」。 3. **org-check 是 PATCH 獨有、其他三個 verb 沒做**:所以只有 PATCH 露出這個不一致。 建議從「create 時 block 實際寫入的 org_id」對比「PATCH org-check 讀的 org_id」兩個值下手,它們應該相等卻不等。 ## 對 arcrun 的影響(已隔離,不阻擋 arcrun Phase 2) - arcrun 已把 `kbdb_patch_block` 降級成 recipe,recipe 的轉發 + auth 注入經驗證**正確無誤**(請求成功打到 KBDB 的 PATCH handler,非 401)。 - 403 屬 KBDB 端行為,依 arcrun 原則「能不能打通由發 key 的服務裁決」,這不是 recipe 的 bug。 - 但 arcrun 的 `kbdb_upsert_block`(GET 查找 → 分支 PATCH/POST)會用到 PATCH,**此 bug 未解前,upsert 的 PATCH 分支無法驗收 2xx**。arcrun 端會把該分支標「未驗收:阻擋於 KBDB PATCH 403」。 KBDB 修好後請通知 arcrun,重跑 `kbdb_patch_block` recipe 驗收即可。