feat(cypher-executor): 同步查詢 trigger + graph_neighbors 查詢面 workflow 示範 #28

Merged
Leo merged 4 commits from feat/sync-query-trigger into main 2026-07-07 09:39:19 +00:00
Owner

動機

現有 named webhook /trigger{success,data,trace,duration_ms} 信封、且只有 POST。查詢面(console/MCP 打 graph neighbors/traverse)需要 GET + 同步 request→response 直接拿最終節點輸出當 HTTP response。補上「同步查詢 trigger」後,任何唯讀查詢端點都能是一條 workflow(很有威力的泛化)。

Part 1:同步查詢 trigger(框架,cypher-executor/src/routes/webhooks-named.ts

沿用既有 executeWebhookGraphawait 拿 result → 回 result.data(最終節點輸出)本身當 response body(非 202、非信封)。四個端點共用一個 queryNamed helper:

  • GET /q/:ns/:name(namespace 走 path,input 走 query string)
  • GET /webhooks/named/:name/query(X-Arcrun-API-Key header,input 走 query string)
  • POST /webhooks/named/:name/query(header,input 走 body)
  • POST /webhooks/named/:ns/:name/query(namespace 走 path,input 走 body)

認證沿用 X-Arcrun-API-Key(或 namespace 走 path,與 /trigger path 版對稱)。
誠實(mindset §7):節點失敗回 {success:false,error,trace} + 500(非假綠);paused 工作流無法同步回答 → 409 明講並指向 ?async=1+resume;輸出 5 MiB 硬上限(超過 413);duration 走 X-Arcrun-Duration-Ms header 不污染 body。

Part 2:graph_neighbors 查詢面 workflow(A 類,registry/examples/graph-neighbors/

http_request 打 base custom domain kbdb.finally.click(避 CF 1042 same-zone)撈 triplet records → code 零件記憶體 BFS(對照 kbdb-graph-plugin graph-traverse.ts:23-51)→ 同步回鄰居。示範把 graph plugin 內建 GET /graph/neighbors 泛化成 workflow。

測試(7 測,全綠)

cypher-executor/tests/query-trigger.test.ts:同步回輸出(非 202)、GET/POST × header/path 四端點、節點失敗回 error+trace(500)、缺 key 401、workflow 不存在 404。用內建 comp_uppercase(純記憶體、無外部 fetch)證明 Part 1 同步 trigger 機制本身可用(確實同步回值而非 202)。tsc --noEmit 乾淨;全套 48 passed(1 個 executor.test.ts 失敗為 main 既有、與本 PR 無關)。BFS 邏輯另以 fixture 離線驗過(directed/undirected/depth/缺 start 錯誤路徑)。

待驗 / 尚未 live

  • graph_neighborscode 零件部署 leo21c 後才能端到端 live(另線處理)→ 標「待驗」。
  • triplet template id 上線前對一次(workflow 已用 {{input.template}} 參數化,未寫死)。

約束遵循

框架碼走 PR(B 類,未部署);graph workflow 是 A 類 workflow.yaml。無 service binding、無 GitHub、未 merge、未部署。只動 cypher-executor + 自己的 workflow 檔(避免與其他 subagent 衝突)。

🤖 Generated with Claude Code

追加(總管交辦,#29 發現):component-loader 白名單補 code

cypher-executor/src/lib/component-loader.tsWASM_HTTP_RUNNER_IDS 原漏 code,workflow 寫 component: code 會落到 step 8 直接「找不到零件」——本 PR 的 graph_neighbors 正用 code 節點,故補在此。URL 走既有 wasmWorkerUrl 通用推導 arcrun-code.{WORKER_SUBDOMAIN}.workers.dev(subdomain 來自 wrangler.toml [vars],self-hosted 注入自己的值;無寫死官方 code.arcrun.dev)。加 tests/component-loader-code.test.ts(2 測:解析成 runner、stub fetch 證打 subdomain 推導 URL)→ 本 PR 測試共 9 測全綠,全套 50 passed。

## 動機 現有 named webhook `/trigger` 回 `{success,data,trace,duration_ms}` 信封、且只有 POST。查詢面(console/MCP 打 graph neighbors/traverse)需要 **GET + 同步 request→response 直接拿最終節點輸出**當 HTTP response。補上「同步查詢 trigger」後,任何唯讀查詢端點都能是一條 workflow(很有威力的泛化)。 ## Part 1:同步查詢 trigger(框架,`cypher-executor/src/routes/webhooks-named.ts`) 沿用既有 `executeWebhookGraph` 但 `await` 拿 result → 回 `result.data`(最終節點輸出)本身當 response body(非 202、非信封)。四個端點共用一個 `queryNamed` helper: - `GET /q/:ns/:name`(namespace 走 path,input 走 query string) - `GET /webhooks/named/:name/query`(X-Arcrun-API-Key header,input 走 query string) - `POST /webhooks/named/:name/query`(header,input 走 body) - `POST /webhooks/named/:ns/:name/query`(namespace 走 path,input 走 body) 認證沿用 `X-Arcrun-API-Key`(或 namespace 走 path,與 `/trigger` path 版對稱)。 **誠實(mindset §7)**:節點失敗回 `{success:false,error,trace}` + 500(非假綠);paused 工作流無法同步回答 → 409 明講並指向 `?async=1`+resume;輸出 **5 MiB 硬上限**(超過 413);duration 走 `X-Arcrun-Duration-Ms` header 不污染 body。 ## Part 2:graph_neighbors 查詢面 workflow(A 類,`registry/examples/graph-neighbors/`) `http_request` 打 base custom domain `kbdb.finally.click`(避 CF 1042 same-zone)撈 triplet records → `code` 零件記憶體 BFS(對照 kbdb-graph-plugin `graph-traverse.ts:23-51`)→ 同步回鄰居。示範把 graph plugin 內建 `GET /graph/neighbors` 泛化成 workflow。 ## 測試(7 測,全綠) `cypher-executor/tests/query-trigger.test.ts`:同步回輸出(非 202)、GET/POST × header/path 四端點、節點失敗回 error+trace(500)、缺 key 401、workflow 不存在 404。用內建 `comp_uppercase`(純記憶體、無外部 fetch)證明 **Part 1 同步 trigger 機制本身可用**(確實同步回值而非 202)。`tsc --noEmit` 乾淨;全套 48 passed(1 個 executor.test.ts 失敗為 main 既有、與本 PR 無關)。BFS 邏輯另以 fixture 離線驗過(directed/undirected/depth/缺 start 錯誤路徑)。 ## 待驗 / 尚未 live - `graph_neighbors` 需 `code` 零件部署 leo21c 後才能端到端 live(另線處理)→ 標「待驗」。 - triplet template id 上線前對一次(workflow 已用 `{{input.template}}` 參數化,未寫死)。 ## 約束遵循 框架碼走 PR(B 類,未部署);graph workflow 是 A 類 workflow.yaml。無 service binding、無 GitHub、未 merge、未部署。只動 cypher-executor + 自己的 workflow 檔(避免與其他 subagent 衝突)。 🤖 Generated with [Claude Code](https://claude.com/claude-code) ## 追加(總管交辦,#29 發現):component-loader 白名單補 `code` `cypher-executor/src/lib/component-loader.ts` 的 `WASM_HTTP_RUNNER_IDS` 原漏 `code`,workflow 寫 `component: code` 會落到 step 8 直接「找不到零件」——本 PR 的 graph_neighbors 正用 code 節點,故補在此。URL 走既有 `wasmWorkerUrl` 通用推導 `arcrun-code.{WORKER_SUBDOMAIN}.workers.dev`(subdomain 來自 wrangler.toml `[vars]`,self-hosted 注入自己的值;無寫死官方 `code.arcrun.dev`)。加 `tests/component-loader-code.test.ts`(2 測:解析成 runner、stub fetch 證打 subdomain 推導 URL)→ 本 PR 測試共 **9 測全綠**,全套 50 passed。
Leo added 1 commit 2026-07-07 08:17:04 +00:00
Part 1(框架,cypher-executor webhooks-named.ts):加同步查詢 trigger。
現有 named webhook /trigger 回 {success,data,trace,duration_ms} 信封、只有 POST;
查詢面(console/MCP 打 graph neighbors/traverse)要 GET + 直接拿最終節點輸出當 response。
新端點同步 await 執行 workflow graph → 回 result.data(最終節點輸出)本身當 body(非 202):
  - GET  /q/:ns/:name                    (namespace 走 path,input 走 query string)
  - GET  /webhooks/named/:name/query     (X-Arcrun-API-Key header,input 走 query string)
  - POST /webhooks/named/:name/query     (header,input 走 body)
  - POST /webhooks/named/:ns/:name/query (namespace 走 path,input 走 body)
認證沿用 X-Arcrun-API-Key。誠實(mindset §7):節點失敗回 error+trace(500,非假綠);
paused 工作流無法同步回答 → 409 明講;輸出 5 MiB 硬上限(超過 413);duration 走 header 不污染 body。

Part 2(A 類 workflow.yaml):registry/examples/graph-neighbors/。
http_request 打 base custom domain kbdb.finally.click(避 CF 1042)撈 triplet records
→ code 零件記憶體 BFS(對照 kbdb-graph-plugin graph-traverse.ts)→ 同步回鄰居。
把 graph plugin 內建 GET /graph/neighbors 泛化成查詢面 workflow 的示範。

測試:cypher-executor/tests/query-trigger.test.ts(7 測,全綠)——同步回輸出(非 202)、
GET/POST × header/path 四端點、節點失敗回錯+trace、缺 key 401、不存在 404。
用內建 comp_uppercase(純記憶體)證明 Part 1 同步 trigger 機制本身可用。

待驗:graph_neighbors 需 code 零件部署 leo21c 後才能 live 端到端(另線處理);
triplet template id 上線前對一次(workflow 已參數化未寫死)。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015d5jDbuqT5Htwv3Q88XXKk
Leo marked the pull request as work in progress 2026-07-07 08:17:20 +00:00
Author
Owner

[總管] ⚠️ 改一處即可 merge

Part 1(同步查詢 trigger) 核實通過:四端點/5 MiB 硬上限(413)/paused 409 指向 async/節點失敗 500 帶 trace——誠實設計都在 code 裡對得上;本機跑測試 48/49,唯一 fail(executor.test「不存在的零件回傳失敗」)在 main 同樣 fail=既有,宣稱屬實。「任何唯讀查詢端點都能是一條 workflow」這步泛化與 leo 的全 workflow 化方向一致。

Part 2(graph-neighbors 示範)🔴 merge 條件:workflow.yaml 寫死官方 kbdb.finally.click——KBDB_BASE_URL fallback(Arcrun#2)同家族坑:self-hosted 用戶照抄示範,查詢(含自己 namespace 與資料流向)直接打進官方庫。要求:base URL 參數化({{input.kbdb_base}} 或 config 佔位),yaml 頂部醒目註明「改成你自己的 KBDB URL」;1042 的解法註解可保留但補「self-hosted 有 global_fetch_strictly_public flag,workers.dev URL 亦可」。

小記(不擋):GET /q/:ns/:name 的 input 走 query string 會進各層 log——文件註明「敏感輸入用 POST /query」即可。

[總管] ⚠️ **改一處即可 merge**。 **Part 1(同步查詢 trigger)✅ 核實通過**:四端點/5 MiB 硬上限(413)/paused 409 指向 async/節點失敗 500 帶 trace——誠實設計都在 code 裡對得上;本機跑測試 48/49,唯一 fail(executor.test「不存在的零件回傳失敗」)**在 main 同樣 fail=既有,宣稱屬實**。「任何唯讀查詢端點都能是一條 workflow」這步泛化與 leo 的全 workflow 化方向一致。 **Part 2(graph-neighbors 示範)🔴 merge 條件**:workflow.yaml 寫死官方 `kbdb.finally.click`——**KBDB_BASE_URL fallback(Arcrun#2)同家族坑**:self-hosted 用戶照抄示範,查詢(含自己 namespace 與資料流向)直接打進官方庫。要求:base URL 參數化(`{{input.kbdb_base}}` 或 config 佔位),yaml 頂部醒目註明「改成你自己的 KBDB URL」;1042 的解法註解可保留但補「self-hosted 有 global_fetch_strictly_public flag,workers.dev URL 亦可」。 小記(不擋):GET `/q/:ns/:name` 的 input 走 query string 會進各層 log——文件註明「敏感輸入用 POST /query」即可。
Leo added 1 commit 2026-07-07 08:42:55 +00:00
WASM_HTTP_RUNNER_IDS 漏 'code',導致 workflow 寫 `component: code` 在解析鏈
step 1-6 全不命中後落到 step 8 直接「找不到零件」——本 PR 的 graph_neighbors
範例正用 code 節點,故歸此分支。

URL 推導:走既有 wasmWorkerUrl 通用推導 arcrun-code.{WORKER_SUBDOMAIN}.workers.dev
(WORKER_SUBDOMAIN 來自 wrangler.toml [vars],self-hosted 由 deploy 注入自己的
subdomain)——無寫死官方 code.arcrun.dev,self-hosted 天然成立。

測試:tests/component-loader-code.test.ts(2 測)——`code` 解析成 runner 不 throw、
stub fetch 證 runner 打 arcrun-code.{sub}.workers.dev;wasmWorkerUrl 對任意 subdomain
推導正確。tsc 乾淨、全套 50 passed(1 失敗為 main 既有、無關)。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015d5jDbuqT5Htwv3Q88XXKk
Leo added 1 commit 2026-07-07 09:01:24 +00:00
審查發現:workflow.yaml 寫死 kbdb.finally.click = KBDB_BASE_URL fallback 同家族坑
(self-hosted 用戶照抄示範,查詢與資料流向直接打進官方庫)。

改法:
- fetch_triplets base URL 參數化為 {{input.kbdb_base}}(每次呼叫帶),yaml 檔頂加醒目
  警示「先改成你自己的 KBDB URL」;grep 證兩檔零 finally.click 殘留。
- 1042 註解保留並補一句:self-hosted 有 global_fetch_strictly_public flag
  (credential-primitives-wasm Phase 7),開了 workers.dev URL 亦可帶。
- description.md 參數表加 kbdb_base(必填)+觸發範例改自有域名佔位+補
  「敏感輸入請用 POST /query(GET /q/ 的 query string 會進各層 log)」。

tsc 乾淨、全套 50 passed(1 失敗為 main 既有 executor.test.ts 斷言漂移,無關)。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015d5jDbuqT5Htwv3Q88XXKk
Author
Owner

[總管] 審查兩點已改完,commit 39d6fdf 已 push 同分支。

1. 🔴 去寫死官方 KBDB URLfetch_triplets.url{{input.kbdb_base}}/records/by-template/...(base URL 每次呼叫帶,workflow 零寫死);yaml 檔頂加醒目警示「先改成你自己的 KBDB URL——抄別人的值=資料流向直接打進別人的庫」。grep finally.click 兩檔(workflow.yaml / description.md)均 0 殘留。1042 註解保留並補:self-hosted 有 global_fetch_strictly_public flag(credential-primitives-wasm Phase 7),開了之後 workers.dev URL 亦可帶。description.md 參數表加 kbdb_base(必填)、觸發範例改 {你的-cypher-domain} / {你的-kbdb-domain} 佔位。

2. 敏感輸入註記 — description.md 觸發段補:「敏感輸入請用 POST /queryGET /q/ 的 query string 會進 CF / proxy / access log 各層日誌」。workflow.yaml 觸發註解也帶一句指回 description.md。

驗證:YAML re-parse OK(flow/config/code 節點結構完整);tsc --noEmit 乾淨;全套 50 passed(唯一失敗為 main 既有 executor.test.ts 斷言漂移,與本分支無關)。本 PR 自身測試維持 9 測全綠。未 merge、未部署。

[總管] 審查兩點已改完,commit `39d6fdf` 已 push 同分支。 **1. 🔴 去寫死官方 KBDB URL** — `fetch_triplets.url` 改 `{{input.kbdb_base}}/records/by-template/...`(base URL 每次呼叫帶,workflow 零寫死);yaml 檔頂加醒目警示「先改成你自己的 KBDB URL——抄別人的值=資料流向直接打進別人的庫」。`grep finally.click` 兩檔(workflow.yaml / description.md)均 **0 殘留**。1042 註解保留並補:self-hosted 有 `global_fetch_strictly_public` flag(credential-primitives-wasm Phase 7),開了之後 workers.dev URL 亦可帶。description.md 參數表加 `kbdb_base`(必填)、觸發範例改 `{你的-cypher-domain}` / `{你的-kbdb-domain}` 佔位。 **2. 敏感輸入註記** — description.md 觸發段補:「敏感輸入請用 `POST /query`;`GET /q/` 的 query string 會進 CF / proxy / access log 各層日誌」。workflow.yaml 觸發註解也帶一句指回 description.md。 **驗證**:YAML re-parse OK(flow/config/code 節點結構完整);`tsc --noEmit` 乾淨;全套 **50 passed**(唯一失敗為 main 既有 `executor.test.ts` 斷言漂移,與本分支無關)。本 PR 自身測試維持 9 測全綠。未 merge、未部署。
Leo added 1 commit 2026-07-07 09:38:15 +00:00
Leo marked the pull request as ready for review 2026-07-07 09:39:18 +00:00
Leo merged commit f7fe080169 into main 2026-07-07 09:39:19 +00:00
Sign in to join this conversation.