頂層 D22 決策(leo 2026-07-03 拍板):推什麼由開發環境歸屬決定, Gitea private=除機敏值/build 產物/.github 外全 push。 解 T1.5 卡點:雲端工人 clone 拿得到 credential-store-migration.md,可就地改寫 SDD。 機敏掃描兩輪通過(新增 189 檔約 2.1MB,node_modules/dist/wasm 照舊排除)。 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
8.5 KiB
2026-05-13 cypher-executor outbound fetch 全失效(CF 同 zone 自循環死鎖)
總耗時:約一整天 debug 根因:Cloudflare Workers 對「綁 custom domain 的 Worker fetch 同 zone 另一個 custom domain Worker」會撞 zone routing 死鎖 → 回 522 修法:cypher-executor fetch component worker 改走
*.workers.dev子域(不同路由系統,繞過 zone proxy) 影響:mira 7B.3c 阻擋一整天;封測 P0 從「全綠」revert 成 #9 阻擋
症狀
mira 跑 acr run wiki_synthesis(5 節點 workflow,含 kbdb_get / claude_api)回:
n1 → {"success": false, "status": 522, "error": "error code: 522"}
每節點精準 ~1000ms timeout 後 522。
進一步測試發現所有 outbound HTTP fetch from cypher-executor 都 522,無論目標是:
- 同 zone:
kbdb-get.arcrun.dev、claude-api.arcrun.dev、cypher.arcrun.dev/health(self) - 外部:
httpbin.org、github.com、google.com
但 service binding 路徑(SVC_STRING_OPS 等 15 個邏輯零件)完全正常。
觀察矩陣
| 路徑 | 結果 |
|---|---|
| 本機 curl → kbdb-get.arcrun.dev | 200 ✓ |
| cypher-executor → kbdb-get.arcrun.dev (HTTP fetch) | 522 |
| cypher-executor → claude-api.arcrun.dev (HTTP fetch) | 522 |
| cypher-executor → httpbin.org (HTTP fetch) | 522 |
| cypher-executor → string_ops (Service Binding) | 200 ✓ |
acr run hello(純 SB 1 節點) |
200 ✓ |
acr run(5 節點純 SB chain,wallTime 2.2s) |
200 ✓ |
| wrangler dev(本機跑 cypher-executor)→ httpbin / kbdb-get | 200 ✓ |
同 src 部署成 arcrun-cypher-executor-probe(純 workers.dev,無 routes 綁定)→ httpbin / kbdb-get / claude-api |
200 ✓ |
最關鍵兩條:
- 本機 wrangler dev 跑同 src,fetch 全通 → 不是 code bug,是 prod 環境問題
- probe worker(同 src、不同 name、走 workers.dev、無 cypher.arcrun.dev route)→ 全通 → 是
cypher.arcrun.dev/*route 觸發的環境問題
誤判路徑(重要 — 避免重犯)
| 假設 | 為什麼錯 |
|---|---|
| A. CF Free Tier 10ms CPU cap(首先猜的) | 5 節點 SB chain 跑 2.2 秒卻通過,CPU cap 假設立刻被推翻。但前期 debug 走了不少彎路 |
| B. 用戶從 Paid 掉到 Free | 用戶確實掉到 Free,當下繳費恢復 Paid,重測仍全 522,徹底排除付費假設 |
| C. compatibility_date 太舊(2025-02-19) | 沒嘗試 bump,但本機 dev 跟 prod 同個 compatibility_date 一通一不通,不是這個 |
| D. 5/8-5/9 manual deploy 推了壞掉的 unpushed commits | git diff 本機 vs origin/main 確實有 3 個 unpushed commits,但檢查 prod bundle 內 makeHttpRunner 跟本機 src 一字不差。code 沒問題 |
| E. Bot Fight Mode / WAF 攔截 outbound fetch | 用戶截圖 zone Security 設定,Bot Fight Mode 未開。不是這個 |
| F. 帳號層 outbound network policy 限制 | dashboard worker bindings 完全乾淨(無 outbound worker / tail consumer / Hyperdrive 等),不是這個 |
| G. CF Worker subrequest quota | wrangler tail 顯示 wallTime: 497ms, cpuTime: 2ms, outcome: ok —— cypher-executor 自己沒撞任何 quota,是 fetch 出去就被攔 |
| H. u6u-mcp service trigger 攔截 | 那是 reverse direction(u6u-mcp 把 cypher-executor 當 service binding 呼叫),跟 outbound fetch 無關 |
共通教訓:522 來自「fetch 出去就被攔截,cypher-executor 不知情把 522 包成 component output 回 client」。wrangler tail 看 cypher-executor outcome 是 ok —— 不要被 worker 自己的 ok 騙了,要看 trace 內 component output 才是真相。
真相
CF Workers 對「綁 custom domain Worker A 用 fetch() 打同 zone 另一個 custom domain Worker B」會撞 zone reverse proxy 路由死鎖。具體機制(推測):
- cypher.arcrun.dev/* route 觸發 → cypher-executor 收到請求
- cypher-executor 內部
fetch("https://kbdb-get.arcrun.dev/")出去 - CF edge 看「目標 hostname 是同 zone (
arcrun.dev),有 worker route」 → 走 zone reverse proxy - 同 zone re-entry 觸發 CF 自循環防護 → fetch 不能完成
- 對 cypher-executor 表現為「fetch 等到 timeout,得到一個假 522 response」
- cypher-executor 不知情,把 522 當作 component 真實回應傳回 client
httpbin.org 也 522 不是 same-zone 問題,可能是「進入 outbound fetch code path 就被同樣機制 abort」的副作用(這部分仍不完全清楚,但實證 workers.dev 路徑無此問題)。
*.workers.dev 不走 zone reverse proxy,是 CF 內部的另一條路由(worker-to-worker internal routing),不撞死鎖。Service Binding 同理(不走網路,process 內呼叫)。
為什麼以前能跑
4/18 arcrun.md 記錄「httpbin_post 端對端驗證通過」,當時 cypher-executor 也是綁 cypher.arcrun.dev/*,也是 fetch *.arcrun.dev,卻能通。推測 CF 之後某次平台更新收緊了 same-zone fetch 防護,但確切時間不可考。
→ 教訓:CF 平台行為會悄悄變,依賴 fetch(*.same-zone.dev) 是脆弱設計,從此架構上不該再依賴。
修法
改 4 個檔案(commit see git log around 2026-05-13):
-
cypher-executor/src/lib/component-loader.ts:wasmWorkerUrl(canonicalId, subdomain)簽名加subdomain參數- URL pattern 從
https://${kebab}.arcrun.dev改為https://arcrun-${kebab}.${subdomain}.workers.dev - 兩個 caller(line 128 / line 192 fallback)同步改
-
cypher-executor/src/actions/auth-dispatcher.ts:wasmWorkerUrl(...)呼叫同步加subdomain參數,從env.WORKER_SUBDOMAIN取
-
cypher-executor/src/types.ts:Bindings加WORKER_SUBDOMAIN: string
-
cypher-executor/wrangler.toml:[vars]加WORKER_SUBDOMAIN = "uncle6-me"
Dashboard 一次性手動操作:5 個 P0 component worker(kbdb-get / kbdb-ingest / kbdb-create-block / kbdb-patch-block / claude-api)→ Settings → Domains & Routes → workers.dev → Enable
未來新增 component worker 時必須:dashboard 啟用 workers.dev URL(rule 03 已加入步驟 5)
驗證
修復後重測同樣 3 個 trigger:
| Trigger | 修復前 | 修復後 |
|---|---|---|
| cypher → kbdb-get | 522 (1064ms) | 200 (2027ms) 拿回真實 block 內容 |
| cypher → claude-api | 522 (1014ms) | 200 (6226ms) Claude 真實回應 |
| cypher → httpbin | 522 (1023ms) | 404 error 1042(不是 522 死鎖了;外部 fetch 限制是另一個問題,不影響 mira) |
mira acr run wiki_synthesis 5 節點 workflow 跑通前 3 節點(load_schema / load_skill / load_entities),後續節點失敗是 mira 業務邏輯問題(Unauthorized 在某個 block id),不是 cypher-executor 平台問題。
影響範圍與善後
影響:
- 任何用 cypher-executor 跑外部 fetch 的 workflow 都壞(封測 Step 2/5/6 / mira / 自架用戶)
- arcrun 「每個零件 = 公開 URL」承諾在純
*.arcrun.dev體系下無法跟「cypher-executor HTTP fetch」並存
善後(已做):
- ✅ rule 01-tech-stack.md:URL 慣例改為「對內 workers.dev / 對外 arcrun.dev」二元
- ✅ rule 03-component-architecture.md:第一核心概念改為「每個零件 = 兩個 URL」,部署步驟加 dashboard workers.dev enable
- ✅ arcrun.md P0 #9 標 resolved 並 reference 本 incident
- ✅ probe worker 已刪
- ⏳ mira tasks.md 7B.3c 解除阻擋(即將)
未來怎麼避免
- 新 component worker 部署 checklist 強制包含 dashboard workers.dev enable(rule 03 已加,但實務上靠 dashboard 容易忘,未來可考慮寫 deploy 後驗證 script)
- 不要再加 outbound HTTP fetch 對同 zone hostname —— cypher-executor 對任何
*.arcrun.dev的 fetch 都該走 workers.dev URL - wrangler dev 是診斷神器 —— 本機跑 prod 同份 src 是區分「環境問題 vs code 問題」最快方法,未來 prod 出怪異行為先跑這個
- wrangler tail outcome:ok 不代表沒問題 —— 要看 component trace output 才是真相
- Self-hosted fork 文件要明寫:必須改
WORKER_SUBDOMAIN+ 所有 component worker dashboard 啟用 workers.dev(rule 03 已加,BETA_TEST.md 待 onboarding 章節加)
Reference
- 對應 SDD:
matrix/arcrun/.agents/specs/arcrun/arcrun.mdP0 #9 - 規範更新:
matrix/arcrun/.claude/rules/01-tech-stack.md、rules/03-component-architecture.md - 受影響 SDD:
polaris/mira/.agents/specs/mira-app/tasks.md7B.3c(阻擋一整天)