# graph-neighbors

## 解決什麼問題
把 graph plugin 內建的 `GET /graph/neighbors`（同步 request→response 拿鄰居）**改寫成一條 workflow**。
示範「查詢面工作流」：查詢端點不必是框架寫死的 route，可以是一條 `workflow.yaml` —— 撈 triplet
記錄 → 記憶體 BFS → 同步回鄰居。任何唯讀查詢都能這樣泛化成 workflow。

## 依賴的框架能力（本 PR 補上的）
**同步查詢 trigger**（cypher-executor `webhooks-named.ts`）：現有 named webhook 的 `/trigger`
回的是 `{success,data,trace,duration_ms}` 信封、且只有 POST。查詢面要 **GET + 直接拿最終節點輸出**。
新端點同步 `await` 執行 graph → 把 `result.data`（最終節點輸出）本身當 response 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）

## 怎麼觸發
```bash
# GET（最像原本的 /graph/neighbors）——{你的-cypher-domain}/{你的-kbdb-domain} 換成自己的部署
curl "https://{你的-cypher-domain}/q/{namespace}/graph_neighbors?node=Arcrun&depth=2&template=graph_triplet&namespace={namespace}&kbdb_base=https://{你的-kbdb-domain}"

# POST（header 認證）
curl -X POST https://{你的-cypher-domain}/webhooks/named/graph_neighbors/query \
  -H "X-Arcrun-API-Key: {namespace}" \
  -d '{"node":"Arcrun","depth":2,"template":"graph_triplet","namespace":"{namespace}","kbdb_base":"https://{你的-kbdb-domain}"}'
```

> ⚠️ **敏感輸入請用 `POST /query`**：`GET /q/` 的參數走 query string，會進 CF / proxy / access log
> 各層日誌；node 名、namespace 等若屬敏感，改走 POST body。
回傳（最終節點輸出本身，非信封）：
```json
{ "success": true, "start": "Arcrun", "depth": 2, "directed": false,
  "neighbors": [ { "node": "cypher-executor", "predicate": "包含", "from": "Arcrun", "depth": 1 } ],
  "count": 1 }
```

## 參數
- `node`（必填）：BFS 起點節點名
- `depth`（預設 1）：最大跳數
- `template`（必填）：triplet 記錄的 base template id（⚠️ 以實際部署的 kbdb-graph-plugin triplet template 為準）
- `namespace`（必填）：租戶 owner_id（self-hosted 明碼 namespace）
- `kbdb_base`（必填）：**你自己的 KBDB base URL**（如 `https://kbdb.example.com`）。
  workflow 不寫死任何一家的庫——抄示範時帶錯（或照抄別人的值）＝查詢與資料流向直接打進別人的庫
  （KBDB_BASE_URL fallback 同家族坑，勿重蹈）。
- `directed`（預設 false）：`true` 只走 subject→object；否則把 triplet 當雙向邊（無向鄰居）

## kbdb_base 該帶哪種 URL（1042）
cypher-executor 對 kbdb 發 fetch，若打同 zone URL 會踩 CF 1042（same-zone self-fetch）。兩條路皆可：
1. 帶 KBDB 的 **custom domain**（跨 zone、走公網前門，天然避開 1042）；
2. self-hosted 有 **`global_fetch_strictly_public`** compatibility flag（credential-primitives-wasm
   Phase 7，cypher wrangler.toml），開了之後 **workers.dev URL 亦可**直接帶。

## ⚠️ 尚未 live 驗（待辦）
- **`code` 零件尚未部署到 leo21c**（另線處理）→ 本工作流無法端到端 live 跑。
  workflow.yaml 已寫好放這裡待驗。
- **同步查詢 trigger 本身已驗**：`cypher-executor/tests/query-trigger.test.ts`（7 測）用內建零件
  （comp_uppercase，純記憶體、無外部 fetch）證明「確實同步回最終節點輸出而非 202」。
- 上線前另需對一次實際 triplet template id（本檔用 `{{input.template}}` 參數化，未寫死）。

## 對照
記憶體 BFS 對照 `kbdb-graph-plugin` 的 `graph-traverse.ts:23-51`：triplet 當有向邊
`subject --predicate--> object`，從起點逐跳擴張到 depth 上限，收集首次訪到的節點當鄰居。

## 學到什麼
- 查詢端點可以是 workflow，不必是框架寫死的 route（同步查詢 trigger 讓這件事成立）
- `code` 零件（sandbox inline JS）承載「非 call-api 的純計算」（BFS），不必為此鑄 domain 零件
- 單一 `{{ref}}` pass-through 保留陣列型別 → `{{fetch_triplets.data.records}}` 拿到真陣列餵給 code
