Files
Arcrun/MIGRATION.md
T
Claude 39e6f59178 feat(workflow-store): workflow 真相源 KV → KBDB API(entry_type=workflow)
SDD kbdb-base §8.3/§8.4 P2+P3。總管裁定 2026-07-06:
① upsert 走 KBDB base PUT /entries(by owner_id+page_name+entry_type)
② cron 掃 KBDB、不保留 KV cron-idx
③ 一 workflow=一筆 entry_type=workflow;content=description(保 embed)、
   graph+config+cron_expr 進 metadata_json

KBDB:
- entry-crud.ts 加 upsertEntry(read-then-write,無 UNIQUE、表不變)
- entries.ts 加 PUT /entries(upsert,回 created 旗標,content 變動時 embed-on-write)

cypher-executor:
- 新增 lib/workflow-store.ts(走 kbdbBase,禁直連 D1)
- webhooks-named register/trigger/list/delete 切雙軌(讀先 KBDB miss fallback KV、
  寫 KBDB 為主+暫雙寫 KV);writeWorkflowSearchEntry 上收進 putWorkflow(修重複 entry bug);
  backfill 升級為 KV→KBDB 遷移入口;移除 migrate-cron-index 端點
- scheduled 改掃 KBDB(listCronWorkflows);刪除 lib/cron-index.ts
- component-loader(trigger_workflow)、executions 擁有權檢查切雙軌讀

tsc 0 error;kbdb vitest 6/6;cypher vitest 41/42(1 失敗為 pre-existing,與本 PR 無關)。
不 merge、不部署、不動 production KV workflow。搬遷步驟見 MIGRATION.md。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HJiLCRUU2o3aSpPEzVCt2o
2026-07-06 13:55:16 +00:00

104 lines
6.7 KiB
Markdown
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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.
# MIGRATION — workflow 真相源 WEBHOOKS KV → KBDB APIentry_type=workflow
> 分支:`feat/workflow-store-kbdb` SDD`system-dev/docs/3-specs/arcrun/kbdb-base/design.md` §8.3/§8.4
> 總管裁定(2026-07-06):① upsert 走 KBDB base `PUT /entries`;② cron 掃 KBDB、不保留 KV cron-idx
> ③ 一 workflow = 一筆 `entry_type=workflow``content=description`(保 embed),graph+config+cron_expr 進 `metadata_json`。
>
> **本 PR 不 merge、不部署、不動 production 那 7 筆 KV workflow。** data 搬遷是下一階段(leo 寫入閘)。
---
## 1. 這個 PR 改了什麼
### KBDB(新增能力)
- `kbdb/src/actions/entry-crud.ts`:新增 `upsertEntry(db, input)` — by `(owner_id, page_name, entry_type)`
read-then-write(無 UNIQUE 約束、表不變鐵律;命中最舊一筆更新,重跑收斂)。
- `kbdb/src/routes/entries.ts`:新增 `PUT /entries`upsert,回 `{ success, entry, created }`content 變動時 embed-on-write)。
### cypher-executorworkflow store + 六路 + 兩路切雙軌)
- **新檔** `cypher-executor/src/lib/workflow-store.ts``getWorkflow / listWorkflows / putWorkflow /
deleteWorkflow / listCronWorkflows`,全走 KBDB base API`kbdbBase` = KBDB_BASE_URL + 選用
KBDB_INTERNAL_TOKEN),owner_id=namespace 租戶隔離。禁直連 D1/SQL。
- `routes/webhooks-named.ts`
- register:寫 `putWorkflow`(KBDB 為主)+ 暫雙寫 KV;移除 `writeWorkflowSearchEntry`(上收進 putWorkflow
修掉每次 POST 堆重複 entry 的 bug);移除 KV cron-idx 維護。
- trigger / list / delete:讀先 KBDB、miss fallback KVlist = KBDB KV(同名 KBDB 為準);delete 兩邊都刪。
- `backfill-search-entries`:升級為 **KV→KBDB 完整遷移入口**putWorkflow upsert,冪等可重跑)。
- 移除 `migrate-cron-index` 端點(KV cron-idx 已退場)。
- `scheduled.ts`cron 掃描改 `listCronWorkflows`(掃 KBDB、記憶體濾 cron_expr);不再讀 KV cron-idx。
- `lib/component-loader.ts`trigger_workflow 子流程)、`routes/executions.ts`(擁有權檢查):切雙軌讀。
- **刪除** `lib/cron-index.ts`KV cron-idx 模型退場)。
### 綠燈
- `kbdb` tsc 0 error、vitest 6/6 綠。
- `cypher-executor` tsc 0 error、vitest 41/42 綠(1 個 `executor.test.ts > 不存在的零件` 失敗為
**pre-existing**main 上同樣失敗,與本 PR 無關——component-not-found 錯誤訊息措辭斷言,非 workflow 路徑)。
---
## 2. 部署後驗證計畫(對真端點 curl,禁 miniflare 假綠)
> 前提:部署到 **leo21c**(auto 模式本輪不做;下述為部署後的驗收步驟)。
> 端點:cypher `https://arcrun-cypher-executor.leo21c.workers.dev`、KBDB `https://arcrun-kbdb.leo21c.workers.dev`。
> **全程只用測試 namespace(如 `ak_wfmigtest`),不碰現有 7 筆 production workflow。**
設 `NS=ak_wfmigtest`、`CY=https://arcrun-cypher-executor.leo21c.workers.dev`、`KB=https://arcrun-kbdb.leo21c.workers.dev`。
1. **KBDB upsert 端點本身**
```
curl -XPUT $KB/entries -H 'content-type: application/json' \
-d '{"entry_type":"workflow","owner_id":"'$NS'","page_name":"t1","content":"desc A","metadata_json":"{\"graph\":{\"id\":\"g\"}}"}'
# → { success:true, created:true }
# 再打一次(改 content:"desc B")→ { success:true, created:false }(同一 entry 更新,非新增)
curl "$KB/entries?entry_type=workflow&owner_id=$NS&page_name=t1" # → 恰 1 筆、content="desc B"
```
2. **register(部署)→ 恰一筆、redeploy 不重複**
```
curl -XPOST $CY/webhooks/named -H "X-Arcrun-API-Key: $NS" -H 'content-type: application/json' \
-d '{"name":"wf_a","description":"測試工作流","graph":{"id":"wf_a","nodes":[]}}'
curl "$KB/entries?entry_type=workflow&owner_id=$NS&page_name=wf_a" # → 恰 1 筆
# 同名再 POST 一次(改 description)→ 仍恰 1 筆、content 更新(驗 upsert 冪等,無重複 entry bug
```
3. **list / trigger / delete 走 KBDB**
```
curl $CY/webhooks/named -H "X-Arcrun-API-Key: $NS" # → 含 wf_a,欄位齊
curl -XPOST $CY/webhooks/named/wf_a/trigger -H "X-Arcrun-API-Key: $NS" -d '{}' # → 執行(讀到 KBDB graph
curl -XDELETE $CY/webhooks/named/wf_a -H "X-Arcrun-API-Key: $NS" # → {deleted:true}
curl "$KB/entries?entry_type=workflow&owner_id=$NS&page_name=wf_a" # → 0 筆
```
4. **cron 掃 KBDB**:部署一個首節點為 cron 的 workflowcron_expr 每分鐘),等 12 分鐘看 `wrangler tail`
`[scheduled] scanned N KBDB cron workflows, k triggered` 有觸發。
5. **雙軌 fallback(不寫 KBDB 的舊 KV workflow 仍可 trigger**:手動塞一筆 `{NS}:wf:legacy` 進 WEBHOOKS KV
(只 KV、不進 KBDB),打 `/webhooks/named/legacy/trigger` → 應 fallback KV 成功執行;`GET /webhooks/named`
應同時列出 KBDB 的與這筆 KV-only 的(union)。
**驗收標準**:上述每步 HTTP status + 回傳體符合預期;特別是「redeploy 同名恆為 1 筆」(upsert 生效)
與「cron 從 KBDB 觸發」。缺任一即不算綠,回報而非假綠(mindset §7)。
---
## 3. 剩餘 data 搬遷步驟(下一階段,leo 寫入閘,本輪別做)
現有 7 筆 production workflow 仍只在 WEBHOOKS KV。雙軌讀讓它們仍可 trigger,但:
- **cron 掃描只看 KBDB** → 若這 7 筆裡有 cron workflow,未搬遷前它們的排程會**停止觸發**(⚠️ 高優先)。
- semantic 搜尋也只看 KBDB entry。
**搬遷程序(冪等、可重跑)**
1. 逐 namespace 呼叫 `POST /workflows/backfill-search-entries`(帶該租戶 `X-Arcrun-API-Key`)。
它 list KV 的 `{ns}:wf:*`、對每筆 `putWorkflow`upsert)遷進 KBDB。回傳 `backfilled` / `needs_description`。
2. 驗證:`GET $KB/entries?entry_type=workflow&owner_id={ns}` 每筆都有對應 entrygraph 在 metadata)。
3. `needs_description` 清單交操盤 CC re-deploy 時據實補描述(不自動編造)。
4. 全部驗穩後,才由 leo 決定**拆掉 register 的 KV 雙寫 + trigger/list/delete 的 KV fallback**(另一次閘)。
拆除前 KV 是安全網,不要急著拿掉。
> 誰有幾筆、哪些是 cron,需先盤點(`WEBHOOKS.list` 或 console)再排搬遷順序(cron 的先搬)。
---
## 4. 回滾
本 PR 不動 production 資料,且 register 仍雙寫 KV、讀有 KV fallback → 直接 revert 分支即可回到「KV 為真相源」。
KBDB 端只**新增** `PUT /entries`(不改既有端點行為),revert cypher 側即停用;KBDB 側可留(無副作用)。
唯一不可逆的取捨:本 PR 刪了 `cron-index.ts` 與 `migrate-cron-index` 端點(KV cron-idx 退場);
如需回滾 cron 到 KV,從 git 歷史取回即可。