Files
kbdb-graph-plugin/docs/5-records/incidents/BUG-2026-05-29-patch-blocks-403-different-org.md
T
Leo efe8e165cf feat: KBDB-graph 插件獨立 — 全面改寫成走基本盤 API(API-as-Wall)
按 leo 鐵律(2026-06-14)把插件從「直接 SQL 操作基本盤表」改寫成
「只透過基本盤 arcrun/kbdb HTTP API 讀寫」。零建表、零 migration、零 SQL。

- 新增 src/lib/kbdb-client.ts:唯一對外通道,封裝 entries/templates/records API
- 新增 src/lib/templates.ts:triplet/entity template 定義(替代建表)
- 改寫 21 個違規 action(triplet/graph/entity/search)→ 走 client,圖在插件層記憶體組裝
- 移除所有 migrations、D1/Vectorize/AI 綁定;embedding/語意搜尋歸基本盤 optional 模組
- index.ts 只掛 triplets/graph/entities/search 路由;基本盤路由歸 arcrun/kbdb
- 測試改走 mock client(純 node);裁剪 CLAUDE.md 只留 graph 插件 + 鐵律
- 修正 SDD design.md「讀現狀推翻鐵律」的錯誤判斷(共用 D1 → API-as-Wall)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-14 20:59:41 +08:00

3.9 KiB
Raw Blame History

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

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

經 arcruncypher-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 降級成 reciperecipe 的轉發 + auth 注入經驗證正確無誤(請求成功打到 KBDB 的 PATCH handler,非 401)。
  • 403 屬 KBDB 端行為,依 arcrun 原則「能不能打通由發 key 的服務裁決」,這不是 recipe 的 bug。
  • 但 arcrun 的 kbdb_upsert_blockGET 查找 → 分支 PATCH/POST)會用到 PATCH此 bug 未解前,upsert 的 PATCH 分支無法驗收 2xx。arcrun 端會把該分支標「未驗收:阻擋於 KBDB PATCH 403」。

KBDB 修好後請通知 arcrun,重跑 kbdb_patch_block recipe 驗收即可。